1600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/* 2600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Conditions Of Use 3600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 4600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * This software was developed by employees of the National Institute of 5600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Standards and Technology (NIST), an agency of the Federal Government. 6600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Pursuant to title 15 Untied States Code Section 105, works of NIST 7600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * employees are not subject to copyright protection in the United States 8600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * and are considered to be in the public domain. As a result, a formal 9600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * license is not needed to use the software. 10600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 11600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * This software is provided by NIST as a service and is expressly 12600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED 13600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF 14600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT 15600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * AND DATA ACCURACY. NIST does not warrant or make any representations 16600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * regarding the use of the software or the results thereof, including but 17600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * not limited to the correctness, accuracy, reliability or usefulness of 18600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * the software. 19600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 20600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Permission to use this software is contingent upon your acceptance 21600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * of the terms of this agreement 22600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 23600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * . 24600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 25600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 26600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/**************************************************************************/ 27600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/* Product of NIST Advanced Networking Technologies Division */ 28600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/**************************************************************************/ 29600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangpackage gov.nist.javax.sip.stack; 30600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 31600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.core.InternalErrorHandler; 32600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.core.NameValueList; 33600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.DialogExt; 34600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.ListeningPointImpl; 35600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.SipListenerExt; 36600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.SipProviderImpl; 37600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.Utils; 38600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.address.AddressImpl; 39600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.address.SipUri; 40600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.Authorization; 41600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.CSeq; 42600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.Contact; 43600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.ContactList; 44600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.From; 45600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.MaxForwards; 46600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.RAck; 47600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.RSeq; 48600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.Reason; 49600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.RecordRoute; 50600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.RecordRouteList; 51600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.Require; 52600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.Route; 53600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.RouteList; 54600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.SIPHeader; 55600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.TimeStamp; 56600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.To; 57600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.Via; 58600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.message.MessageFactoryImpl; 59600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.message.SIPMessage; 60600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.message.SIPRequest; 61600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.message.SIPResponse; 62600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 63600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.io.IOException; 64600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.io.PrintWriter; 65600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.io.Serializable; 66600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.io.StringWriter; 67600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.net.InetAddress; 68600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.text.ParseException; 69600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.util.ArrayList; 70600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.util.Iterator; 71600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.util.LinkedList; 72600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.util.List; 73600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.util.ListIterator; 74600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.util.Set; 75600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.util.concurrent.CopyOnWriteArraySet; 76600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.util.concurrent.Semaphore; 77600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.util.concurrent.TimeUnit; 78600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 79600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.ClientTransaction; 80600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.DialogDoesNotExistException; 81600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.DialogState; 82600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.IOExceptionEvent; 83600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.InvalidArgumentException; 84600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.ListeningPoint; 85600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.ObjectInUseException; 86600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.SipException; 87600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.Transaction; 88600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.TransactionDoesNotExistException; 89600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.TransactionState; 90600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.address.Address; 91600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.address.Hop; 92600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.address.SipURI; 93600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.header.CallIdHeader; 94600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.header.ContactHeader; 95600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.header.EventHeader; 96600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.header.OptionTag; 97600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.header.RAckHeader; 98600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.header.RSeqHeader; 99600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.header.ReasonHeader; 100600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.header.RequireHeader; 101600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.header.RouteHeader; 102600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.header.SupportedHeader; 103600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.header.TimeStampHeader; 104600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.message.Request; 105600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.message.Response; 106600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 107600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/* 108600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Acknowledgements: 109600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 110600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Bugs in this class were reported by Antonis Karydas, Brad Templeton, Jeff Adams, Alex Rootham , 111600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Martin Le Clerk, Christophe Anzille, Andreas Bystrom, Lebing Xie, Jeroen van Bemmel. Hagai Sela 112600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * reported a bug in updating the route set (on RE-INVITE). Jens Tinfors submitted a bug fix and 113600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * the .equals method. Jan Schaumloeffel contributed a buf fix ( memory leak was happening when 114600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 180 contained a To tag. 115600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 116600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 117600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 118600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/** 119600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Tracks dialogs. A dialog is a peer to peer association of communicating SIP entities. For 120600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * INVITE transactions, a Dialog is created when a success message is received (i.e. a response 121600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * that has a To tag). The SIP Protocol stores enough state in the message structure to extract a 122600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * dialog identifier that can be used to retrieve this structure from the SipStack. 123600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 124600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @version 1.2 $Revision: 1.159 $ $Date: 2010/01/08 15:14:12 $ 125600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 126600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @author M. Ranganathan 127600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 128600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 129600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 130600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 131600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangpublic class SIPDialog implements javax.sip.Dialog, DialogExt { 132600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 133600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private static final long serialVersionUID = -1429794423085204069L; 134600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 135600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private transient boolean dialogTerminatedEventDelivered; // prevent duplicate 136600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 137600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private transient String stackTrace; // for semaphore debugging. 138600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 139600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private String method; 140600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 141600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // delivery of the event 142600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private transient boolean isAssigned; 143600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 144600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private boolean reInviteFlag; 145600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 146600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private transient Object applicationData; // Opaque pointer to application data. 147600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 148600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private transient SIPRequest originalRequest; 149600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 150600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Last response (JvB: either sent or received). 151600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private SIPResponse lastResponse; 152600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 153600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Should be transient, in case the dialog is serialized it will be null 154600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // so when a subsequent request will be sent it will be set and a new message channel can be 155600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // created 156600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private transient SIPTransaction firstTransaction; 157600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 158600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private transient SIPTransaction lastTransaction; 159600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 160600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private String dialogId; 161600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 162600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private transient String earlyDialogId; 163600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 164600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private long localSequenceNumber; 165600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 166600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private long remoteSequenceNumber; 167600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 168600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected String myTag; 169600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 170600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected String hisTag; 171600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 172600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private RouteList routeList; 173600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 174600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private transient SIPTransactionStack sipStack; 175600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 176600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private int dialogState; 177600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 178600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected transient boolean ackSeen; 179600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 180600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private transient SIPRequest lastAckSent; 181600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 182600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private SIPRequest lastAckReceived; 183600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 184600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // could be set on recovery by examining the method looks like a duplicate of ackSeen 185600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected transient boolean ackProcessed; 186600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 187600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected transient DialogTimerTask timerTask; 188600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 189600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected transient Long nextSeqno; 190600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 191600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private transient int retransmissionTicksLeft; 192600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 193600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private transient int prevRetransmissionTicks; 194600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 195600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private long originalLocalSequenceNumber; 196600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 197600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // This is for debugging only. 198600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private transient int ackLine; 199600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 200600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Audit tag used by the SIP Stack audit 201600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public transient long auditTag = 0; 202600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 203600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // The following fields are extracted from the request that created the 204600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Dialog. 205600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 206600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected javax.sip.address.Address localParty; 207600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 208600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected javax.sip.address.Address remoteParty; 209600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 210600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected CallIdHeader callIdHeader; 211600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 212600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public final static int NULL_STATE = -1; 213600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 214600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public final static int EARLY_STATE = DialogState._EARLY; 215600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 216600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public final static int CONFIRMED_STATE = DialogState._CONFIRMED; 217600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 218600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public final static int TERMINATED_STATE = DialogState._TERMINATED; 219600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 220600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // the amount of time to keep this dialog around before the stack GC's it 221600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 222600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private static final int DIALOG_LINGER_TIME = 8; 223600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 224600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private boolean serverTransactionFlag; 225600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 226600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private transient SipProviderImpl sipProvider; 227600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 228600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private boolean terminateOnBye; 229600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 230600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private transient boolean byeSent; // Flag set when BYE is sent, to disallow new 231600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 232600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // requests 233600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 234600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private Address remoteTarget; 235600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 236600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private EventHeader eventHeader; // for Subscribe notify 237600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 238600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Stores the last OK for the INVITE 239600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Used in createAck. 240600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private transient long lastInviteOkReceived; 241600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 242600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private transient Semaphore ackSem = new Semaphore(1); 243600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 244600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private transient int reInviteWaitTime = 100; 245600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 246600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private transient DialogDeleteTask dialogDeleteTask; 247600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 248600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private transient DialogDeleteIfNoAckSentTask dialogDeleteIfNoAckSentTask; 249600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 250600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private transient boolean isAcknowledged; 251600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 252600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private transient long highestSequenceNumberAcknowledged = -1; 253600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 254600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private boolean isBackToBackUserAgent; 255600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 256600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private boolean sequenceNumberValidation = true; 257600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 258600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // List of event listeners for this dialog 259600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private transient Set<SIPDialogEventListener> eventListeners; 260600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // added for Issue 248 : https://jain-sip.dev.java.net/issues/show_bug.cgi?id=248 261600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private Semaphore timerTaskLock = new Semaphore(1); 262600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 263600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // We store here the useful data from the first transaction without having to 264600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // keep the whole transaction object for the duration of the dialog. It also 265600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // contains the non-transient information used in the replication of dialogs. 266600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected boolean firstTransactionSecure; 267600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected boolean firstTransactionSeen; 268600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected String firstTransactionMethod; 269600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected String firstTransactionId; 270600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected boolean firstTransactionIsServerTransaction; 271600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected int firstTransactionPort = 5060; 272600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected Contact contactHeader; 273600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 274600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // ////////////////////////////////////////////////////// 275600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Inner classes 276600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // ////////////////////////////////////////////////////// 277600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 278600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 279600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * This task waits till a pending ACK has been recorded and then sends out a re-INVITE. This 280600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * is to prevent interleaving INVITEs ( which will result in a 493 from the UA that receives 281600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * the out of order INVITE). This is primarily for B2BUA support. A B2BUA may send a delayed 282600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * ACK while it does mid call codec renegotiation. In the meanwhile, it cannot send an intervening 283600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * re-INVITE otherwise the othr end will respond with a REQUEST_PENDING. We want to avoid this 284600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * condition. Hence we wait till the ACK for the previous re-INVITE has been sent before 285600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * sending the next re-INVITE. 286600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 287600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public class ReInviteSender implements Runnable, Serializable { 288600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private static final long serialVersionUID = 1019346148741070635L; 289600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang ClientTransaction ctx; 290600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 291600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public void terminate() { 292600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 293600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang ctx.terminate(); 294600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang Thread.currentThread().interrupt(); 295600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } catch (ObjectInUseException e) { 296600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logError("unexpected error", e); 297600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 298600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 299600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 300600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public ReInviteSender(ClientTransaction ctx) { 301600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.ctx = ctx; 302600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 303600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 304600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public void run() { 305600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 306600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang long timeToWait = 0; 307600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang long startTime = System.currentTimeMillis(); 308600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 309600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (!SIPDialog.this.takeAckSem()) { 310600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 311600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Could not send re-INVITE fire a timeout on the INVITE. 312600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 313600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) 314600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logError( 315600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang "Could not send re-INVITE time out ClientTransaction"); 316600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang ((SIPClientTransaction) ctx).fireTimeoutTimer(); 317600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 318600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Send BYE to the Dialog. 319600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 320600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if ( sipProvider.getSipListener() != null && sipProvider.getSipListener() instanceof SipListenerExt ) { 321600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang raiseErrorEvent(SIPDialogErrorEvent.DIALOG_REINVITE_TIMEOUT); 322600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else { 323600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang Request byeRequest = SIPDialog.this.createRequest(Request.BYE); 324600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if ( MessageFactoryImpl.getDefaultUserAgentHeader() != null ) { 325600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang byeRequest.addHeader(MessageFactoryImpl.getDefaultUserAgentHeader()); 326600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 327600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang ReasonHeader reasonHeader = new Reason(); 328600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang reasonHeader.setCause(1024); 329600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang reasonHeader.setText("Timed out waiting to re-INVITE"); 330600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang byeRequest.addHeader(reasonHeader); 331600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang ClientTransaction byeCtx = SIPDialog.this.getSipProvider().getNewClientTransaction(byeRequest); 332600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SIPDialog.this.sendRequest(byeCtx); 333600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return; 334600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 335600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 336600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (getState() != DialogState.TERMINATED) { 337600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 338600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang timeToWait = System.currentTimeMillis() - startTime; 339600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 340600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 341600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 342600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * If we had to wait for ACK then wait for the ACK to actually get to the other 343600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * side. Wait for any ACK retransmissions to finish. Then send out the request. 344600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * This is a hack in support of some UA that want re-INVITEs to be spaced out in 345600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * time ( else they return a 400 error code ). 346600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 347600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 348600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (timeToWait != 0) { 349600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang Thread.sleep(SIPDialog.this.reInviteWaitTime); 350600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 351600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } catch (InterruptedException ex) { 352600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) 353600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug("Interrupted sleep"); 354600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return; 355600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 356600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (SIPDialog.this.getState() != DialogState.TERMINATED) { 357600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SIPDialog.this.sendRequest(ctx, true); 358600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 359600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) 360600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug("re-INVITE successfully sent"); 361600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } catch (Exception ex) { 362600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logError("Error sending re-INVITE", ex); 363600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } finally { 364600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.ctx = null; 365600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 366600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 367600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 368600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 369600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang class LingerTimer extends SIPStackTimerTask implements Serializable { 370600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 371600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public LingerTimer() { 372600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 373600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 374600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 375600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected void runTask() { 376600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SIPDialog dialog = SIPDialog.this; 377600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if(eventListeners != null) { 378600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang eventListeners.clear(); 379600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 380600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang timerTaskLock = null; 381600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.removeDialog(dialog); 382600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 383600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 384600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 385600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 386600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang class DialogTimerTask extends SIPStackTimerTask implements Serializable { 387600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang int nRetransmissions; 388600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 389600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SIPServerTransaction transaction; 390600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 391600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public DialogTimerTask(SIPServerTransaction transaction) { 392600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.transaction = transaction; 393600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.nRetransmissions = 0; 394600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 395600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 396600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected void runTask() { 397600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // If I ACK has not been seen on Dialog, 398600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // resend last response. 399600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SIPDialog dialog = SIPDialog.this; 400600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) 401600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug("Running dialog timer"); 402600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang nRetransmissions++; 403600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SIPServerTransaction transaction = this.transaction; 404600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 405600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Issue 106. Section 13.3.1.4 RFC 3261 The 2xx response is passed to the transport 406600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * with an interval that starts at T1 seconds and doubles for each retransmission 407600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * until it reaches T2 seconds If the server retransmits the 2xx response for 64*T1 408600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * seconds without receiving an ACK, the dialog is confirmed, but the session SHOULD 409600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * be terminated. 410600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 411600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 412600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (nRetransmissions > 64 * SIPTransaction.T1) { 413600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipProvider.getSipListener() != null && sipProvider.getSipListener() instanceof SipListenerExt ) { 414600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang raiseErrorEvent(SIPDialogErrorEvent.DIALOG_ACK_NOT_RECEIVED_TIMEOUT); 415600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else { 416600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang dialog.delete(); 417600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 418600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (transaction != null 419600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang && transaction.getState() != javax.sip.TransactionState.TERMINATED) { 420600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang transaction.raiseErrorEvent(SIPTransactionErrorEvent.TIMEOUT_ERROR); 421600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 422600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else if ((!dialog.ackSeen) && (transaction != null)) { 423600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Retransmit to 200 until ack receivedialog. 424600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SIPResponse response = transaction.getLastResponse(); 425600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (response.getStatusCode() == 200) { 426600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 427600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 428600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // resend the last response. 429600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (dialog.toRetransmitFinalResponse(transaction.T2)) 430600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang transaction.sendMessage(response); 431600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 432600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } catch (IOException ex) { 433600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 434600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang raiseIOException(transaction.getPeerAddress(), transaction.getPeerPort(), 435600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang transaction.getPeerProtocol()); 436600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 437600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } finally { 438600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Need to fire the timer so 439600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // transaction will eventually 440600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // time out whether or not 441600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // the IOException occurs 442600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Note that this firing also 443600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // drives Listener timeout. 444600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SIPTransactionStack stack = dialog.sipStack; 445600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (stack.isLoggingEnabled()) { 446600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang stack.getStackLogger().logDebug("resend 200 response from " + dialog); 447600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 448600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang transaction.fireTimer(); 449600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 450600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 451600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 452600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 453600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Stop running this timer if the dialog is in the 454600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // confirmed state or ack seen if retransmit filter on. 455600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (dialog.isAckSeen() || dialog.dialogState == TERMINATED_STATE) { 456600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.transaction = null; 457600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.cancel(); 458600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 459600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 460600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 461600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 462600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 463600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 464600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 465600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 466600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * This timer task is used to garbage collect the dialog after some time. 467600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 468600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 469600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 470600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang class DialogDeleteTask extends SIPStackTimerTask implements Serializable { 471600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 472600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected void runTask() { 473600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang delete(); 474600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 475600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 476600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 477600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 478600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 479600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * This timer task is used to garbage collect the dialog after some time. 480600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 481600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 482600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 483600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang class DialogDeleteIfNoAckSentTask extends SIPStackTimerTask implements Serializable { 484600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private long seqno; 485600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 486600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public DialogDeleteIfNoAckSentTask(long seqno) { 487600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.seqno = seqno; 488600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 489600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 490600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected void runTask() { 491600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (SIPDialog.this.highestSequenceNumberAcknowledged < seqno) { 492600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 493600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Did not send ACK so we need to delete the dialog. 494600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * B2BUA NOTE: we may want to send BYE to the Dialog at this 495600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * point. Do we want to make this behavior tailorable? 496600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 497600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang dialogDeleteIfNoAckSentTask = null; 498600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if ( !SIPDialog.this.isBackToBackUserAgent) { 499600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) 500600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logError("ACK Was not sent. killing dialog"); 501600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if ( ((SipProviderImpl)sipProvider).getSipListener() instanceof SipListenerExt ){ 502600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang raiseErrorEvent(SIPDialogErrorEvent.DIALOG_ACK_NOT_SENT_TIMEOUT); 503600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else { 504600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang delete(); 505600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 506600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else { 507600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) 508600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logError("ACK Was not sent. Sending BYE"); 509600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if ( ((SipProviderImpl)sipProvider).getSipListener() instanceof SipListenerExt ){ 510600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang raiseErrorEvent(SIPDialogErrorEvent.DIALOG_ACK_NOT_SENT_TIMEOUT); 511600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else { 512600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 513600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 514600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Send BYE to the Dialog. 515600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * This will be removed for the next spec revision. 516600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 517600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 518600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang Request byeRequest = SIPDialog.this.createRequest(Request.BYE); 519600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if ( MessageFactoryImpl.getDefaultUserAgentHeader() != null ) { 520600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang byeRequest.addHeader(MessageFactoryImpl.getDefaultUserAgentHeader()); 521600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 522600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang ReasonHeader reasonHeader = new Reason(); 523600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang reasonHeader.setProtocol("SIP"); 524600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang reasonHeader.setCause(1025); 525600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang reasonHeader.setText("Timed out waiting to send ACK"); 526600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang byeRequest.addHeader(reasonHeader); 527600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang ClientTransaction byeCtx = SIPDialog.this.getSipProvider().getNewClientTransaction(byeRequest); 528600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SIPDialog.this.sendRequest(byeCtx); 529600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return; 530600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } catch (Exception ex) { 531600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SIPDialog.this.delete(); 532600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 533600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 534600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 535600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 536600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 537600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 538600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 539600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 540600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // /////////////////////////////////////////////////////////// 541600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Constructors. 542600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // /////////////////////////////////////////////////////////// 543600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 544600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Protected Dialog constructor. 545600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 546600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private SIPDialog(SipProviderImpl provider) { 547600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.terminateOnBye = true; 548600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.routeList = new RouteList(); 549600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.dialogState = NULL_STATE; // not yet initialized. 550600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang localSequenceNumber = 0; 551600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang remoteSequenceNumber = -1; 552600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.sipProvider = provider; 553600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang eventListeners = new CopyOnWriteArraySet<SIPDialogEventListener>(); 554600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 555600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 556600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private void recordStackTrace() { 557600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang StringWriter stringWriter = new StringWriter(); 558600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang PrintWriter writer = new PrintWriter(stringWriter); 559600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang new Exception().printStackTrace(writer); 560600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.stackTrace = stringWriter.getBuffer().toString(); 561600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 562600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 563600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 564600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Constructor given the first transaction. 565600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 566600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @param transaction is the first transaction. 567600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 568600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public SIPDialog(SIPTransaction transaction) { 569600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this(transaction.getSipProvider()); 570600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 571600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SIPRequest sipRequest = (SIPRequest) transaction.getRequest(); 572600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.callIdHeader = sipRequest.getCallId(); 573600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.earlyDialogId = sipRequest.getDialogId(false); 574600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (transaction == null) 575600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new NullPointerException("Null tx"); 576600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.sipStack = transaction.sipStack; 577600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 578600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // this.defaultRouter = new DefaultRouter((SipStack) sipStack, 579600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // sipStack.outboundProxy); 580600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 581600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.sipProvider = (SipProviderImpl) transaction.getSipProvider(); 582600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipProvider == null) 583600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new NullPointerException("Null Provider!"); 584600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.addTransaction(transaction); 585600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) { 586600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug("Creating a dialog : " + this); 587600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug( 588600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang "provider port = " + this.sipProvider.getListeningPoint().getPort()); 589600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logStackTrace(); 590600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 591600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.isBackToBackUserAgent = sipStack.isBackToBackUserAgent; 592600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang addEventListener(sipStack); 593600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 594600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 595600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 596600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Constructor given a transaction and a response. 597600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 598600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @param transaction -- the transaction ( client/server) 599600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @param sipResponse -- response with the appropriate tags. 600600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 601600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public SIPDialog(SIPClientTransaction transaction, SIPResponse sipResponse) { 602600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this(transaction); 603600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipResponse == null) 604600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new NullPointerException("Null SipResponse"); 605600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.setLastResponse(transaction, sipResponse); 606600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.isBackToBackUserAgent = sipStack.isBackToBackUserAgent; 607600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 608600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 609600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 610600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * create a sip dialog with a response ( no tx) 611600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 612600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public SIPDialog(SipProviderImpl sipProvider, SIPResponse sipResponse) { 613600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this(sipProvider); 614600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.sipStack = (SIPTransactionStack) sipProvider.getSipStack(); 615600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.setLastResponse(null, sipResponse); 616600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.localSequenceNumber = sipResponse.getCSeq().getSeqNumber(); 617600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.originalLocalSequenceNumber = localSequenceNumber; 618600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.myTag = sipResponse.getFrom().getTag(); 619600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.hisTag = sipResponse.getTo().getTag(); 620600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.localParty = sipResponse.getFrom().getAddress(); 621600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.remoteParty = sipResponse.getTo().getAddress(); 622600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.method = sipResponse.getCSeq().getMethod(); 623600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.callIdHeader = sipResponse.getCallId(); 624600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.serverTransactionFlag = false; 625600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) { 626600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug("Creating a dialog : " + this); 627600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logStackTrace(); 628600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 629600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.isBackToBackUserAgent = sipStack.isBackToBackUserAgent; 630600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang addEventListener(sipStack); 631600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 632600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 633600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // /////////////////////////////////////////////////////////// 634600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Private methods 635600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // /////////////////////////////////////////////////////////// 636600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 637600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * A debugging print routine. 638600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 639600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private void printRouteList() { 640600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) { 641600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug("this : " + this); 642600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug("printRouteList : " + this.routeList.encode()); 643600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 644600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 645600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 646600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 647600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Return true if this is a client dialog. 648600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 649600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @return true if the transaction that created this dialog is a client transaction and false 650600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * otherwise. 651600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 652600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private boolean isClientDialog() { 653600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SIPTransaction transaction = (SIPTransaction) this.getFirstTransaction(); 654600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return transaction instanceof SIPClientTransaction; 655600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 656600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 657600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 658600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Raise an io exception for asyncrhonous retransmission of responses 659600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 660600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @param host -- host to where the io was headed 661600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @param port -- remote port 662600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @param protocol -- protocol (udp/tcp/tls) 663600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 664600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private void raiseIOException(String host, int port, String protocol) { 665600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Error occured in retransmitting response. 666600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Deliver the error event to the listener 667600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Kill the dialog. 668600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 669600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang IOExceptionEvent ioError = new IOExceptionEvent(this, host, port, protocol); 670600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipProvider.handleEvent(ioError, null); 671600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 672600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang setState(SIPDialog.TERMINATED_STATE); 673600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 674600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 675600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 676600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Raise a dialog timeout if an ACK has not been sent or received 677600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 678600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @param dialogTimeoutError 679600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 680600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private void raiseErrorEvent(int dialogTimeoutError) { 681600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Error event to send to all listeners 682600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SIPDialogErrorEvent newErrorEvent; 683600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Iterator through the list of listeners 684600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang Iterator<SIPDialogEventListener> listenerIterator; 685600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Next listener in the list 686600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SIPDialogEventListener nextListener; 687600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 688600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Create the error event 689600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang newErrorEvent = new SIPDialogErrorEvent(this, dialogTimeoutError); 690600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 691600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Loop through all listeners of this transaction 692600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang synchronized (eventListeners) { 693600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang listenerIterator = eventListeners.iterator(); 694600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang while (listenerIterator.hasNext()) { 695600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Send the event to the next listener 696600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang nextListener = (SIPDialogEventListener) listenerIterator.next(); 697600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang nextListener.dialogErrorEvent(newErrorEvent); 698600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 699600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 700600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Clear the event listeners after propagating the error. 701600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang eventListeners.clear(); 702600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Errors always terminate a dialog except if a timeout has occured because an ACK was not sent or received, then it is the responsibility of the app to terminate 703600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // the dialog, either by sending a BYE or by calling delete() on the dialog 704600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if(dialogTimeoutError != SIPDialogErrorEvent.DIALOG_ACK_NOT_SENT_TIMEOUT && 705600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang dialogTimeoutError != SIPDialogErrorEvent.DIALOG_ACK_NOT_RECEIVED_TIMEOUT && 706600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang dialogTimeoutError != SIPDialogErrorEvent.DIALOG_REINVITE_TIMEOUT ) { 707600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang delete(); 708600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 709600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // we stop the timer in any case 710600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang stopTimer(); 711600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 712600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 713600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 714600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Set the remote party for this Dialog. 715600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 716600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @param sipMessage -- SIP Message to extract the relevant information from. 717600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 718600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private void setRemoteParty(SIPMessage sipMessage) { 719600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 720600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (!isServer()) { 721600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 722600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.remoteParty = sipMessage.getTo().getAddress(); 723600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else { 724600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.remoteParty = sipMessage.getFrom().getAddress(); 725600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 726600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 727600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) { 728600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug("settingRemoteParty " + this.remoteParty); 729600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 730600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 731600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 732600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 733600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Add a route list extracted from a record route list. If this is a server dialog then we 734600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * assume that the record are added to the route list IN order. If this is a client dialog 735600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * then we assume that the record route headers give us the route list to add in reverse 736600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * order. 737600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 738600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @param recordRouteList -- the record route list from the incoming message. 739600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 740600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 741600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private void addRoute(RecordRouteList recordRouteList) { 742600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 743600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.isClientDialog()) { 744600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // This is a client dialog so we extract the record 745600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // route from the response and reverse its order to 746600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // careate a route list. 747600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.routeList = new RouteList(); 748600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // start at the end of the list and walk backwards 749600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 750600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang ListIterator li = recordRouteList.listIterator(recordRouteList.size()); 751600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang boolean addRoute = true; 752600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang while (li.hasPrevious()) { 753600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang RecordRoute rr = (RecordRoute) li.previous(); 754600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 755600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (addRoute) { 756600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang Route route = new Route(); 757600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang AddressImpl address = ((AddressImpl) ((AddressImpl) rr.getAddress()) 758600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang .clone()); 759600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 760600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang route.setAddress(address); 761600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang route.setParameters((NameValueList) rr.getParameters().clone()); 762600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 763600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.routeList.add(route); 764600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 765600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 766600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else { 767600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // This is a server dialog. The top most record route 768600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // header is the one that is closest to us. We extract the 769600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // route list in the same order as the addresses in the 770600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // incoming request. 771600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.routeList = new RouteList(); 772600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang ListIterator li = recordRouteList.listIterator(); 773600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang boolean addRoute = true; 774600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang while (li.hasNext()) { 775600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang RecordRoute rr = (RecordRoute) li.next(); 776600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 777600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (addRoute) { 778600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang Route route = new Route(); 779600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang AddressImpl address = ((AddressImpl) ((AddressImpl) rr.getAddress()) 780600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang .clone()); 781600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang route.setAddress(address); 782600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang route.setParameters((NameValueList) rr.getParameters().clone()); 783600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang routeList.add(route); 784600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 785600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 786600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 787600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } finally { 788600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.getStackLogger().isLoggingEnabled()) { 789600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang Iterator it = routeList.iterator(); 790600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 791600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang while (it.hasNext()) { 792600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SipURI sipUri = (SipURI) (((Route) it.next()).getAddress().getURI()); 793600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (!sipUri.hasLrParam()) { 794600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) { 795600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logWarning( 796600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang "NON LR route in Route set detected for dialog : " + this); 797600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logStackTrace(); 798600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 799600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 800600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 801600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 802600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 803600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 804600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 805600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 806600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Add a route list extacted from the contact list of the incoming message. 807600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 808600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @param contactList -- contact list extracted from the incoming message. 809600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 810600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 811600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 812600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang void setRemoteTarget(ContactHeader contact) { 813600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.remoteTarget = contact.getAddress(); 814600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) { 815600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug("Dialog.setRemoteTarget: " + this.remoteTarget); 816600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logStackTrace(); 817600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 818600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 819600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 820600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 821600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 822600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Extract the route information from this SIP Message and add the relevant information to the 823600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * route set. 824600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 825600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @param sipMessage is the SIP message for which we want to add the route. 826600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 827600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private synchronized void addRoute(SIPResponse sipResponse) { 828600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 829600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 830600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) { 831600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug( 832600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang "setContact: dialogState: " + this + "state = " + this.getState()); 833600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 834600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipResponse.getStatusCode() == 100) { 835600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Do nothing for trying messages. 836600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return; 837600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else if (this.dialogState == TERMINATED_STATE) { 838600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Do nothing if the dialog state is terminated. 839600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return; 840600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else if (this.dialogState == CONFIRMED_STATE) { 841600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // cannot add route list after the dialog is initialized. 842600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Remote target is updated on RE-INVITE but not 843600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // the route list. 844600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipResponse.getStatusCode() / 100 == 2 && !this.isServer()) { 845600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang ContactList contactList = sipResponse.getContactHeaders(); 846600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (contactList != null 847600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang && SIPRequest.isTargetRefresh(sipResponse.getCSeq().getMethod())) { 848600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.setRemoteTarget((ContactHeader) contactList.getFirst()); 849600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 850600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 851600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return; 852600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 853600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 854600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Update route list on response if I am a client dialog. 855600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (!isServer()) { 856600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 857600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // only update the route set if the dialog is not in the confirmed state. 858600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.getState() != DialogState.CONFIRMED 859600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang && this.getState() != DialogState.TERMINATED) { 860600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang RecordRouteList rrlist = sipResponse.getRecordRouteHeaders(); 861600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Add the route set from the incoming response in reverse 862600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // order for record route headers. 863600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (rrlist != null) { 864600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.addRoute(rrlist); 865600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else { 866600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Set the rotue list to the last seen route list. 867600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.routeList = new RouteList(); 868600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 869600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 870600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 871600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang ContactList contactList = sipResponse.getContactHeaders(); 872600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (contactList != null) { 873600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.setRemoteTarget((ContactHeader) contactList.getFirst()); 874600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 875600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 876600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 877600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } finally { 878600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) { 879600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logStackTrace(); 880600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 881600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 882600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 883600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 884600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 885600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Get a cloned copy of route list for the Dialog. 886600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 887600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @return -- a cloned copy of the dialog route list. 888600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 889600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private synchronized RouteList getRouteList() { 890600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) 891600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug("getRouteList " + this); 892600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Find the top via in the route list. 893600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang ListIterator li; 894600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang RouteList retval = new RouteList(); 895600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 896600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang retval = new RouteList(); 897600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.routeList != null) { 898600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang li = routeList.listIterator(); 899600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang while (li.hasNext()) { 900600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang Route route = (Route) li.next(); 901600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang retval.add((Route) route.clone()); 902600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 903600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 904600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 905600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) { 906600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug("----- "); 907600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug("getRouteList for " + this); 908600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (retval != null) 909600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug("RouteList = " + retval.encode()); 910600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (routeList != null) 911600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug("myRouteList = " + routeList.encode()); 912600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug("----- "); 913600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 914600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return retval; 915600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 916600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 917600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang void setRouteList(RouteList routeList) { 918600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.routeList = routeList; 919600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 920600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 921600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 922600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Sends ACK Request to the remote party of this Dialogue. 923600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 924600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 925600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @param request the new ACK Request message to send. 926600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @param throwIOExceptionAsSipException - throws SipException if IOEx encountered. Otherwise, 927600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * no exception is propagated. 928600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @param releaseAckSem - release ack semaphore. 929600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @throws SipException if implementation cannot send the ACK Request for any other reason 930600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 931600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 932600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private void sendAck(Request request, boolean throwIOExceptionAsSipException) 933600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throws SipException { 934600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SIPRequest ackRequest = (SIPRequest) request; 935600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) 936600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug("sendAck" + this); 937600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 938600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (!ackRequest.getMethod().equals(Request.ACK)) 939600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new SipException("Bad request method -- should be ACK"); 940600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.getState() == null || this.getState().getValue() == EARLY_STATE) { 941600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) { 942600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logError( 943600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang "Bad Dialog State for " + this + " dialogID = " + this.getDialogId()); 944600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 945600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new SipException("Bad dialog state " + this.getState()); 946600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 947600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 948600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (!this.getCallId().getCallId().equals(((SIPRequest) request).getCallId().getCallId())) { 949600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) { 950600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logError("CallID " + this.getCallId()); 951600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logError( 952600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang "RequestCallID = " + ackRequest.getCallId().getCallId()); 953600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logError("dialog = " + this); 954600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 955600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new SipException("Bad call ID in request"); 956600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 957600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 958600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) { 959600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug( 960600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang "setting from tag For outgoing ACK= " + this.getLocalTag()); 961600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug( 962600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang "setting To tag for outgoing ACK = " + this.getRemoteTag()); 963600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug("ack = " + ackRequest); 964600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 965600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.getLocalTag() != null) 966600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang ackRequest.getFrom().setTag(this.getLocalTag()); 967600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.getRemoteTag() != null) 968600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang ackRequest.getTo().setTag(this.getRemoteTag()); 969600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } catch (ParseException ex) { 970600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new SipException(ex.getMessage()); 971600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 972600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 973600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang Hop hop = sipStack.getNextHop(ackRequest); 974600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Hop hop = defaultRouter.getNextHop(ackRequest); 975600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (hop == null) 976600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new SipException("No route!"); 977600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 978600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) 979600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug("hop = " + hop); 980600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang ListeningPointImpl lp = (ListeningPointImpl) this.sipProvider.getListeningPoint(hop 981600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang .getTransport()); 982600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (lp == null) 983600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new SipException("No listening point for this provider registered at " 984600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang + hop); 985600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang InetAddress inetAddress = InetAddress.getByName(hop.getHost()); 986600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang MessageChannel messageChannel = lp.getMessageProcessor().createMessageChannel( 987600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang inetAddress, hop.getPort()); 988600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang boolean releaseAckSem = false; 989600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang long cseqNo = ((SIPRequest)request).getCSeq().getSeqNumber(); 990600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (!this.isAckSent(cseqNo)) { 991600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang releaseAckSem = true; 992600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 993600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 994600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.setLastAckSent(ackRequest); 995600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang messageChannel.sendMessage(ackRequest); 996600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Sent atleast one ACK. 997600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.isAcknowledged = true; 998600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.highestSequenceNumberAcknowledged = Math.max(this.highestSequenceNumberAcknowledged, 999600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang ((SIPRequest)ackRequest).getCSeq().getSeqNumber()); 1000600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (releaseAckSem && this.isBackToBackUserAgent) { 1001600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.releaseAckSem(); 1002600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else { 1003600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if ( sipStack.isLoggingEnabled() ) { 1004600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug("Not releasing ack sem for " + this + " isAckSent " + releaseAckSem ); 1005600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1006600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1007600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } catch (IOException ex) { 1008600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (throwIOExceptionAsSipException) 1009600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new SipException("Could not send ack", ex); 1010600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.raiseIOException(hop.getHost(), hop.getPort(), hop.getTransport()); 1011600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } catch (SipException ex) { 1012600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) 1013600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logException(ex); 1014600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw ex; 1015600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } catch (Exception ex) { 1016600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) 1017600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logException(ex); 1018600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new SipException("Could not create message channel", ex); 1019600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1020600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.dialogDeleteTask != null) { 1021600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.dialogDeleteTask.cancel(); 1022600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.dialogDeleteTask = null; 1023600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1024600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.ackSeen = true; 1025600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1026600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1027600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1028600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // ///////////////////////////////////////////////////////////// 1029600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Package local methods 1030600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // ///////////////////////////////////////////////////////////// 1031600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1032600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 1033600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Set the stack address. Prevent us from routing messages to ourselves. 1034600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1035600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @param sipStack the address of the SIP stack. 1036600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1037600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1038600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang void setStack(SIPTransactionStack sipStack) { 1039600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.sipStack = sipStack; 1040600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1041600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1042600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1043600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 1044600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Get the stack . 1045600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1046600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @return sipStack the SIP stack of the dialog. 1047600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1048600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1049600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SIPTransactionStack getStack() { 1050600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return sipStack; 1051600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1052600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1053600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 1054600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Return True if this dialog is terminated on BYE. 1055600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1056600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1057600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang boolean isTerminatedOnBye() { 1058600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1059600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return this.terminateOnBye; 1060600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1061600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1062600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 1063600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Mark that the dialog has seen an ACK. 1064600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1065600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang void ackReceived(SIPRequest sipRequest) { 1066600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1067600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Suppress retransmission of the final response 1068600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.ackSeen) 1069600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return; 1070600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SIPServerTransaction tr = this.getInviteTransaction(); 1071600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (tr != null) { 1072600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (tr.getCSeq() == sipRequest.getCSeq().getSeqNumber()) { 1073600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang acquireTimerTaskSem(); 1074600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 1075600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.timerTask != null) { 1076600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.timerTask.cancel(); 1077600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.timerTask = null; 1078600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1079600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } finally { 1080600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang releaseTimerTaskSem(); 1081600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1082600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.ackSeen = true; 1083600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.dialogDeleteTask != null) { 1084600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.dialogDeleteTask.cancel(); 1085600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.dialogDeleteTask = null; 1086600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1087600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.setLastAckReceived(sipRequest); 1088600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) { 1089600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug( 1090600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang "ackReceived for " + ((SIPTransaction) tr).getMethod()); 1091600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.ackLine = sipStack.getStackLogger().getLineCount(); 1092600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.printDebugInfo(); 1093600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1094600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.isBackToBackUserAgent) { 1095600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.releaseAckSem(); 1096600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1097600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.setState(CONFIRMED_STATE); 1098600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1099600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1100600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1101600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1102600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 1103600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Return true if a terminated event was delivered to the application as a result of the 1104600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * dialog termination. 1105600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1106600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1107600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang synchronized boolean testAndSetIsDialogTerminatedEventDelivered() { 1108600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang boolean retval = this.dialogTerminatedEventDelivered; 1109600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.dialogTerminatedEventDelivered = true; 1110600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return retval; 1111600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1112600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1113600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // ///////////////////////////////////////////////////////// 1114600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Public methods 1115600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // ///////////////////////////////////////////////////////// 1116600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1117600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 1118600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Adds a new event listener to this dialog. 1119600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1120600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @param newListener 1121600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Listener to add. 1122600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1123600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public void addEventListener(SIPDialogEventListener newListener) { 1124600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang eventListeners.add(newListener); 1125600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1126600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1127600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 1128600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Removed an event listener from this dialog. 1129600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1130600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @param oldListener 1131600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Listener to remove. 1132600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1133600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public void removeEventListener(SIPDialogEventListener oldListener) { 1134600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang eventListeners.remove(oldListener); 1135600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1136600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1137600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 1138600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @see javax.sip.Dialog#setApplicationData() 1139600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1140600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public void setApplicationData(Object applicationData) { 1141600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.applicationData = applicationData; 1142600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1143600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1144600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 1145600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * (non-Javadoc) 1146600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1147600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @see javax.sip.Dialog#getApplicationData() 1148600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1149600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public Object getApplicationData() { 1150600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return this.applicationData; 1151600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1152600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1153600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 1154600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Updates the next consumable seqno. 1155600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1156600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1157600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public synchronized void requestConsumed() { 1158600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.nextSeqno = Long.valueOf(this.getRemoteSeqNumber() + 1); 1159600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1160600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) { 1161600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.sipStack.getStackLogger().logDebug( 1162600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang "Request Consumed -- next consumable Request Seqno = " + this.nextSeqno); 1163600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1164600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1165600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1166600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1167600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 1168600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Return true if this request can be consumed by the dialog. 1169600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1170600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @param dialogRequest is the request to check with the dialog. 1171600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @return true if the dialogRequest sequence number matches the next consumable seqno. 1172600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1173600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public synchronized boolean isRequestConsumable(SIPRequest dialogRequest) { 1174600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // have not yet set remote seqno - this is a fresh 1175600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (dialogRequest.getMethod().equals(Request.ACK)) 1176600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new RuntimeException("Illegal method"); 1177600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1178600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // For loose validation this function is delegated to the application 1179600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (!this.isSequnceNumberValidation()) { 1180600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return true; 1181600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1182600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1183600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // JvB: Acceptable iff remoteCSeq < cseq. remoteCSeq==-1 1184600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // when not defined yet, so that works too 1185600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return remoteSequenceNumber < dialogRequest.getCSeq().getSeqNumber(); 1186600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1187600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1188600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 1189600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * This method is called when a forked dialog is created from the client side. It starts a 1190600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * timer task. If the timer task expires before an ACK is sent then the dialog is cancelled 1191600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * (i.e. garbage collected ). 1192600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1193600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1194600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public void doDeferredDelete() { 1195600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.getTimer() == null) 1196600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.setState(TERMINATED_STATE); 1197600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang else { 1198600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.dialogDeleteTask = new DialogDeleteTask(); 1199600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Delete the transaction after the max ack timeout. 1200600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getTimer().schedule(this.dialogDeleteTask, 1201600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SIPTransaction.TIMER_H * SIPTransactionStack.BASE_TIMER_INTERVAL); 1202600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1203600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1204600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1205600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1206600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 1207600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Set the state for this dialog. 1208600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1209600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @param state is the state to set for the dialog. 1210600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1211600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1212600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public void setState(int state) { 1213600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) { 1214600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug( 1215600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang "Setting dialog state for " + this + "newState = " + state); 1216600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logStackTrace(); 1217600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (state != NULL_STATE && state != this.dialogState) 1218600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) { 1219600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug( 1220600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this + " old dialog state is " + this.getState()); 1221600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug( 1222600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this + " New dialog state is " + DialogState.getObject(state)); 1223600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1224600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1225600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1226600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.dialogState = state; 1227600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Dialog is in terminated state set it up for GC. 1228600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (state == TERMINATED_STATE) { 1229600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.getTimer() != null) { // may be null after shutdown 1230600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getTimer().schedule(new LingerTimer(), DIALOG_LINGER_TIME * 1000); 1231600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1232600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.stopTimer(); 1233600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1234600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1235600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1236600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1237600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 1238600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Debugging print for the dialog. 1239600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1240600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public void printDebugInfo() { 1241600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) { 1242600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug("isServer = " + isServer()); 1243600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug("localTag = " + getLocalTag()); 1244600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug("remoteTag = " + getRemoteTag()); 1245600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug("localSequenceNumer = " + getLocalSeqNumber()); 1246600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug("remoteSequenceNumer = " + getRemoteSeqNumber()); 1247600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug("ackLine:" + this.getRemoteTag() + " " + ackLine); 1248600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1249600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1250600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1251600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 1252600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Return true if the dialog has already seen the ack. 1253600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1254600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @return flag that records if the ack has been seen. 1255600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1256600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public boolean isAckSeen() { 1257600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return this.ackSeen; 1258600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1259600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1260600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 1261600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Get the last ACK for this transaction. 1262600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1263600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public SIPRequest getLastAckSent() { 1264600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return this.lastAckSent; 1265600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1266600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1267600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 1268600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Return true if ACK was sent ( for client tx ). For server tx, this is a NO-OP ( we dont 1269600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * send ACK). 1270600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1271600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public boolean isAckSent(long cseqNo) { 1272600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.getLastTransaction() == null) 1273600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return true; 1274600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.getLastTransaction() instanceof ClientTransaction) { 1275600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.getLastAckSent() == null) { 1276600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return false; 1277600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else { 1278600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return cseqNo <=((SIPRequest) this.getLastAckSent()).getCSeq().getSeqNumber(); 1279600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1280600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else { 1281600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return true; 1282600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1283600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1284600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1285600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 1286600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Get the transaction that created this dialog. 1287600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1288600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public Transaction getFirstTransaction() { 1289600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return this.firstTransaction; 1290600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1291600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1292600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1293600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 1294600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Gets the route set for the dialog. When acting as an User Agent Server the route set MUST 1295600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * be set to the list of URIs in the Record-Route header field from the request, taken in 1296600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * order and preserving all URI parameters. When acting as an User Agent Client the route set 1297600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * MUST be set to the list of URIs in the Record-Route header field from the response, taken 1298600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * in reverse order and preserving all URI parameters. If no Record-Route header field is 1299600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * present in the request or response, the route set MUST be set to the empty set. This route 1300600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * set, even if empty, overrides any pre-existing route set for future requests in this 1301600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * dialog. 1302600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * <p> 1303600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Requests within a dialog MAY contain Record-Route and Contact header fields. However, these 1304600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * requests do not cause the dialog's route set to be modified. 1305600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * <p> 1306600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * The User Agent Client uses the remote target and route set to build the Request-URI and 1307600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Route header field of the request. 1308600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1309600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @return an Iterator containing a list of route headers to be used for forwarding. Empty 1310600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * iterator is returned if route has not been established. 1311600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1312600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public Iterator getRouteSet() { 1313600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.routeList == null) { 1314600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return new LinkedList().listIterator(); 1315600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else { 1316600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return this.getRouteList().listIterator(); 1317600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1318600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1319600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1320600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 1321600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Add a Route list extracted from a SIPRequest to this Dialog. 1322600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1323600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @param sipRequest 1324600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1325600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public synchronized void addRoute(SIPRequest sipRequest) { 1326600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) { 1327600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug( 1328600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang "setContact: dialogState: " + this + "state = " + this.getState()); 1329600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1330600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1331600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.dialogState == CONFIRMED_STATE 1332600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang && SIPRequest.isTargetRefresh(sipRequest.getMethod())) { 1333600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.doTargetRefresh(sipRequest); 1334600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1335600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.dialogState == CONFIRMED_STATE || this.dialogState == TERMINATED_STATE) { 1336600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return; 1337600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1338600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1339600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Fix for issue #225: mustn't learn Route set from mid-dialog requests 1340600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if ( sipRequest.getToTag()!=null ) return; 1341600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1342600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Incoming Request has the route list 1343600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang RecordRouteList rrlist = sipRequest.getRecordRouteHeaders(); 1344600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Add the route set from the incoming response in reverse 1345600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // order 1346600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (rrlist != null) { 1347600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.addRoute(rrlist); 1348600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else { 1349600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Set the rotue list to the last seen route list. 1350600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.routeList = new RouteList(); 1351600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1352600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1353600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // put the contact header from the incoming request into 1354600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // the route set. JvB: some duplication here, ref. doTargetRefresh 1355600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang ContactList contactList = sipRequest.getContactHeaders(); 1356600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (contactList != null) { 1357600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.setRemoteTarget((ContactHeader) contactList.getFirst()); 1358600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1359600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1360600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1361600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 1362600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Set the dialog identifier. 1363600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1364600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public void setDialogId(String dialogId) { 1365600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.dialogId = dialogId; 1366600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1367600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1368600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 1369600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Creates a new dialog based on a received NOTIFY. The dialog state is initialized 1370600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * appropriately. The NOTIFY differs in the From tag 1371600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1372600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Made this a separate method to clearly distinguish what's happening here - this is a 1373600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * non-trivial case 1374600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1375600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @param subscribeTx - the transaction started with the SUBSCRIBE that we sent 1376600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @param notifyST - the ServerTransaction created for an incoming NOTIFY 1377600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @return -- a new dialog created from the subscribe original SUBSCRIBE transaction. 1378600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1379600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1380600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1381600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public static SIPDialog createFromNOTIFY(SIPClientTransaction subscribeTx, 1382600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SIPTransaction notifyST) { 1383600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SIPDialog d = new SIPDialog(notifyST); 1384600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // 1385600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // The above sets d.firstTransaction to NOTIFY (ST), correct that 1386600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // 1387600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang d.serverTransactionFlag = false; 1388600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // they share this one 1389600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang d.lastTransaction = subscribeTx; 1390600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang storeFirstTransactionInfo(d, subscribeTx); 1391600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang d.terminateOnBye = false; 1392600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang d.localSequenceNumber = subscribeTx.getCSeq(); 1393600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SIPRequest not = (SIPRequest) notifyST.getRequest(); 1394600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang d.remoteSequenceNumber = not.getCSeq().getSeqNumber(); 1395600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang d.setDialogId(not.getDialogId(true)); 1396600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang d.setLocalTag(not.getToTag()); 1397600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang d.setRemoteTag(not.getFromTag()); 1398600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // to properly create the Dialog object. 1399600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // If not the stack will throw an exception when creating the response. 1400600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang d.setLastResponse(subscribeTx, subscribeTx.getLastResponse()); 1401600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1402600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Dont use setLocal / setRemote here, they make other assumptions 1403600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang d.localParty = not.getTo().getAddress(); 1404600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang d.remoteParty = not.getFrom().getAddress(); 1405600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1406600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // initialize d's route set based on the NOTIFY. Any proxies must have 1407600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Record-Routed 1408600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang d.addRoute(not); 1409600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang d.setState(CONFIRMED_STATE); // set state, *after* setting route set! 1410600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return d; 1411600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1412600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1413600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 1414600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Return true if is server. 1415600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1416600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @return true if is server transaction created this dialog. 1417600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1418600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public boolean isServer() { 1419600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.firstTransactionSeen == false) 1420600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return this.serverTransactionFlag; 1421600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang else 1422600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return this.firstTransactionIsServerTransaction; 1423600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1424600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1425600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1426600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 1427600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Return true if this is a re-establishment of the dialog. 1428600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1429600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @return true if the reInvite flag is set. 1430600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1431600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected boolean isReInvite() { 1432600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return this.reInviteFlag; 1433600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1434600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1435600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 1436600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Get the id for this dialog. 1437600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1438600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @return the string identifier for this dialog. 1439600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1440600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1441600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public String getDialogId() { 1442600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1443600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.dialogId == null && this.lastResponse != null) 1444600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.dialogId = this.lastResponse.getDialogId(isServer()); 1445600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1446600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return this.dialogId; 1447600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1448600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1449600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private static void storeFirstTransactionInfo(SIPDialog dialog, SIPTransaction transaction) { 1450600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang dialog.firstTransaction = transaction; 1451600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang dialog.firstTransactionSeen = true; 1452600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang dialog.firstTransactionIsServerTransaction = transaction.isServerTransaction(); 1453600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang dialog.firstTransactionSecure = transaction.getRequest().getRequestURI().getScheme() 1454600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang .equalsIgnoreCase("sips"); 1455600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang dialog.firstTransactionPort = transaction.getPort(); 1456600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang dialog.firstTransactionId = transaction.getBranchId(); 1457600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang dialog.firstTransactionMethod = transaction.getMethod(); 1458600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1459600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (dialog.isServer()) { 1460600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SIPServerTransaction st = (SIPServerTransaction) transaction; 1461600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SIPResponse response = st.getLastResponse(); 1462600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang dialog.contactHeader = response != null ? response.getContactHeader() : null; 1463600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else { 1464600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SIPClientTransaction ct = (SIPClientTransaction) transaction; 1465600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (ct != null){ 1466600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SIPRequest sipRequest = ct.getOriginalRequest(); 1467600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang dialog.contactHeader = sipRequest.getContactHeader(); 1468600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1469600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1470600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1471600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 1472600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Add a transaction record to the dialog. 1473600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1474600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @param transaction is the transaction to add to the dialog. 1475600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1476600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public void addTransaction(SIPTransaction transaction) { 1477600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1478600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SIPRequest sipRequest = (SIPRequest) transaction.getOriginalRequest(); 1479600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1480600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Proessing a re-invite. 1481600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (firstTransactionSeen && !firstTransactionId.equals(transaction.getBranchId()) 1482600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang && transaction.getMethod().equals(firstTransactionMethod)) { 1483600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.reInviteFlag = true; 1484600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1485600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1486600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (firstTransactionSeen == false) { 1487600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Record the local and remote sequenc 1488600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // numbers and the from and to tags for future 1489600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // use on this dialog. 1490600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang storeFirstTransactionInfo(this, transaction); 1491600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipRequest.getMethod().equals(Request.SUBSCRIBE)) 1492600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.eventHeader = (EventHeader) sipRequest.getHeader(EventHeader.NAME); 1493600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1494600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.setLocalParty(sipRequest); 1495600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.setRemoteParty(sipRequest); 1496600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.setCallId(sipRequest); 1497600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.originalRequest == null) { 1498600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.originalRequest = sipRequest; 1499600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1500600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.method == null) { 1501600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.method = sipRequest.getMethod(); 1502600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1503600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1504600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (transaction instanceof SIPServerTransaction) { 1505600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.hisTag = sipRequest.getFrom().getTag(); 1506600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // My tag is assigned when sending response 1507600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else { 1508600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang setLocalSequenceNumber(sipRequest.getCSeq().getSeqNumber()); 1509600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.originalLocalSequenceNumber = localSequenceNumber; 1510600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.myTag = sipRequest.getFrom().getTag(); 1511600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (myTag == null) 1512600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) 1513600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logError( 1514600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang "The request's From header is missing the required Tag parameter."); 1515600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1516600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else if (transaction.getMethod().equals(firstTransactionMethod) 1517600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang && firstTransactionIsServerTransaction != transaction.isServerTransaction()) { 1518600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // This case occurs when you are processing a re-invite. 1519600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Switch from client side to server side for re-invite 1520600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // (put the other side on hold). 1521600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1522600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang storeFirstTransactionInfo(this, transaction); 1523600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1524600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.setLocalParty(sipRequest); 1525600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.setRemoteParty(sipRequest); 1526600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.setCallId(sipRequest); 1527600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.originalRequest = sipRequest; 1528600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.method = sipRequest.getMethod(); 1529600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1530600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1531600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (transaction instanceof SIPServerTransaction) 1532600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang setRemoteSequenceNumber(sipRequest.getCSeq().getSeqNumber()); 1533600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1534600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // If this is a server transaction record the remote 1535600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // sequence number to avoid re-processing of requests 1536600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // with the same sequence number directed towards this 1537600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // dialog. 1538600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1539600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.lastTransaction = transaction; 1540600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // set a back ptr in the incoming dialog. 1541600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // CHECKME -- why is this here? 1542600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // transaction.setDialog(this,sipRequest); 1543600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) { 1544600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger() 1545600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang .logDebug("Transaction Added " + this + myTag + "/" + hisTag); 1546600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug( 1547600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang "TID = " + transaction.getTransactionId() + "/" 1548600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang + transaction.isServerTransaction()); 1549600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logStackTrace(); 1550600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1551600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1552600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1553600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 1554600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Set the remote tag. 1555600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1556600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @param hisTag is the remote tag to set. 1557600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1558600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private void setRemoteTag(String hisTag) { 1559600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) { 1560600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug( 1561600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang "setRemoteTag(): " + this + " remoteTag = " + this.hisTag + " new tag = " 1562600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang + hisTag); 1563600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1564600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.hisTag != null && hisTag != null && !hisTag.equals(this.hisTag)) { 1565600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.getState() != DialogState.EARLY) { 1566600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) 1567600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug( 1568600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang "Dialog is already established -- ignoring remote tag re-assignment"); 1569600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return; 1570600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else if (sipStack.isRemoteTagReassignmentAllowed()) { 1571600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) 1572600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug( 1573600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang "UNSAFE OPERATION ! tag re-assignment " + this.hisTag 1574600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang + " trying to set to " + hisTag 1575600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang + " can cause unexpected effects "); 1576600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang boolean removed = false; 1577600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.sipStack.getDialog(dialogId) == this) { 1578600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.sipStack.removeDialog(dialogId); 1579600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang removed = true; 1580600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1581600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1582600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Force recomputation of Dialog ID; 1583600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.dialogId = null; 1584600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.hisTag = hisTag; 1585600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (removed) { 1586600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) 1587600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug("ReInserting Dialog"); 1588600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.sipStack.putDialog(this); 1589600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1590600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1591600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else { 1592600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (hisTag != null) { 1593600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.hisTag = hisTag; 1594600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else { 1595600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) 1596600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logWarning("setRemoteTag : called with null argument "); 1597600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1598600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1599600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1600600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1601600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 1602600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Get the last transaction from the dialog. 1603600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1604600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public SIPTransaction getLastTransaction() { 1605600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return this.lastTransaction; 1606600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1607600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1608600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 1609600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Get the INVITE transaction (null if no invite transaction). 1610600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1611600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public SIPServerTransaction getInviteTransaction() { 1612600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang DialogTimerTask t = this.timerTask; 1613600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (t != null) 1614600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return t.transaction; 1615600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang else 1616600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return null; 1617600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1618600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1619600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 1620600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Set the local sequece number for the dialog (defaults to 1 when the dialog is created). 1621600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1622600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @param lCseq is the local cseq number. 1623600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1624600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1625600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private void setLocalSequenceNumber(long lCseq) { 1626600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) 1627600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug( 1628600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang "setLocalSequenceNumber: original " + this.localSequenceNumber + " new = " 1629600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang + lCseq); 1630600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (lCseq <= this.localSequenceNumber) 1631600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new RuntimeException("Sequence number should not decrease !"); 1632600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.localSequenceNumber = lCseq; 1633600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1634600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1635600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 1636600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Set the remote sequence number for the dialog. 1637600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1638600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @param rCseq is the remote cseq number. 1639600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1640600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1641600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public void setRemoteSequenceNumber(long rCseq) { 1642600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) 1643600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug("setRemoteSeqno " + this + "/" + rCseq); 1644600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.remoteSequenceNumber = rCseq; 1645600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1646600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1647600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 1648600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Increment the local CSeq # for the dialog. This is useful for if you want to create a hole 1649600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * in the sequence number i.e. route a request outside the dialog and then resume within the 1650600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * dialog. 1651600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1652600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public void incrementLocalSequenceNumber() { 1653600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang ++this.localSequenceNumber; 1654600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1655600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1656600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 1657600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Get the remote sequence number (for cseq assignment of outgoing requests within this 1658600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * dialog). 1659600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1660600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @deprecated 1661600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @return local sequence number. 1662600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1663600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1664600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public int getRemoteSequenceNumber() { 1665600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return (int) this.remoteSequenceNumber; 1666600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1667600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1668600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 1669600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Get the local sequence number (for cseq assignment of outgoing requests within this 1670600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * dialog). 1671600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1672600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @deprecated 1673600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @return local sequence number. 1674600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1675600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1676600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public int getLocalSequenceNumber() { 1677600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return (int) this.localSequenceNumber; 1678600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1679600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1680600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 1681600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Get the sequence number for the request that origianlly created the Dialog. 1682600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1683600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @return -- the original starting sequence number for this dialog. 1684600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1685600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public long getOriginalLocalSequenceNumber() { 1686600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return this.originalLocalSequenceNumber; 1687600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1688600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1689600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 1690600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * (non-Javadoc) 1691600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1692600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @see javax.sip.Dialog#getLocalSequenceNumberLong() 1693600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1694600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public long getLocalSeqNumber() { 1695600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return this.localSequenceNumber; 1696600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1697600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1698600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 1699600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * (non-Javadoc) 1700600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1701600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @see javax.sip.Dialog#getRemoteSequenceNumberLong() 1702600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1703600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public long getRemoteSeqNumber() { 1704600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return this.remoteSequenceNumber; 1705600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1706600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1707600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 1708600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * (non-Javadoc) 1709600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1710600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @see javax.sip.Dialog#getLocalTag() 1711600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1712600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public String getLocalTag() { 1713600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return this.myTag; 1714600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1715600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1716600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 1717600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * (non-Javadoc) 1718600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1719600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @see javax.sip.Dialog#getRemoteTag() 1720600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1721600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public String getRemoteTag() { 1722600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1723600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return hisTag; 1724600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1725600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1726600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 1727600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Set local tag for the transaction. 1728600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1729600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @param mytag is the tag to use in From headers client transactions that belong to this 1730600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * dialog and for generating To tags for Server transaction requests that belong to 1731600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * this dialog. 1732600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1733600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private void setLocalTag(String mytag) { 1734600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) { 1735600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug("set Local tag " + mytag + " " + this.dialogId); 1736600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logStackTrace(); 1737600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1738600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1739600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.myTag = mytag; 1740600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1741600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1742600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1743600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 1744600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * (non-Javadoc) 1745600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1746600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @see javax.sip.Dialog#delete() 1747600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1748600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1749600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public void delete() { 1750600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // the reaper will get him later. 1751600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.setState(TERMINATED_STATE); 1752600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1753600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1754600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 1755600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * (non-Javadoc) 1756600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1757600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @see javax.sip.Dialog#getCallId() 1758600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1759600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public CallIdHeader getCallId() { 1760600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return this.callIdHeader; 1761600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1762600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1763600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 1764600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * set the call id header for this dialog. 1765600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1766600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private void setCallId(SIPRequest sipRequest) { 1767600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.callIdHeader = sipRequest.getCallId(); 1768600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1769600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1770600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 1771600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * (non-Javadoc) 1772600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1773600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @see javax.sip.Dialog#getLocalParty() 1774600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1775600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1776600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public javax.sip.address.Address getLocalParty() { 1777600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return this.localParty; 1778600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1779600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1780600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private void setLocalParty(SIPMessage sipMessage) { 1781600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (!isServer()) { 1782600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.localParty = sipMessage.getFrom().getAddress(); 1783600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else { 1784600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.localParty = sipMessage.getTo().getAddress(); 1785600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1786600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1787600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1788600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 1789600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Returns the Address identifying the remote party. This is the value of the To header of 1790600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * locally initiated requests in this dialogue when acting as an User Agent Client. 1791600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * <p> 1792600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * This is the value of the From header of recieved responses in this dialogue when acting as 1793600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * an User Agent Server. 1794600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1795600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @return the address object of the remote party. 1796600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1797600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public javax.sip.address.Address getRemoteParty() { 1798600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1799600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) { 1800600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug("gettingRemoteParty " + this.remoteParty); 1801600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1802600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return this.remoteParty; 1803600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1804600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1805600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1806600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 1807600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * (non-Javadoc) 1808600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1809600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @see javax.sip.Dialog#getRemoteTarget() 1810600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1811600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public javax.sip.address.Address getRemoteTarget() { 1812600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1813600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return this.remoteTarget; 1814600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1815600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1816600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 1817600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * (non-Javadoc) 1818600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1819600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @see javax.sip.Dialog#getState() 1820600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1821600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public DialogState getState() { 1822600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.dialogState == NULL_STATE) 1823600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return null; // not yet initialized 1824600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return DialogState.getObject(this.dialogState); 1825600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1826600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1827600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 1828600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Returns true if this Dialog is secure i.e. if the request arrived over TLS, and the 1829600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Request-URI contained a SIPS URI, the "secure" flag is set to TRUE. 1830600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1831600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @return <code>true</code> if this dialogue was established using a sips URI over TLS, and 1832600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * <code>false</code> otherwise. 1833600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1834600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public boolean isSecure() { 1835600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return this.firstTransactionSecure; 1836600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1837600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1838600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 1839600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * (non-Javadoc) 1840600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1841600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @see javax.sip.Dialog#sendAck(javax.sip.message.Request) 1842600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1843600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public void sendAck(Request request) throws SipException { 1844600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.sendAck(request, true); 1845600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1846600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1847600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 1848600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * (non-Javadoc) 1849600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1850600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @see javax.sip.Dialog#createRequest(java.lang.String) 1851600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1852600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public Request createRequest(String method) throws SipException { 1853600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1854600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (method.equals(Request.ACK) || method.equals(Request.PRACK)) { 1855600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new SipException("Invalid method specified for createRequest:" + method); 1856600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1857600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (lastResponse != null) 1858600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return this.createRequest(method, this.lastResponse); 1859600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang else 1860600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new SipException("Dialog not yet established -- no response!"); 1861600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1862600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1863600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 1864600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * The method that actually does the work of creating a request. 1865600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1866600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @param method 1867600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @param response 1868600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @return 1869600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @throws SipException 1870600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1871600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private Request createRequest(String method, SIPResponse sipResponse) throws SipException { 1872600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 1873600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Check if the dialog is in the right state (RFC 3261 section 15). The caller's UA MAY 1874600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * send a BYE for either CONFIRMED or EARLY dialogs, and the callee's UA MAY send a BYE on 1875600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * CONFIRMED dialogs, but MUST NOT send a BYE on EARLY dialogs. 1876600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1877600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Throw out cancel request. 1878600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1879600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1880600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (method == null || sipResponse == null) 1881600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new NullPointerException("null argument"); 1882600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1883600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (method.equals(Request.CANCEL)) 1884600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new SipException("Dialog.createRequest(): Invalid request"); 1885600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1886600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.getState() == null 1887600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang || (this.getState().getValue() == TERMINATED_STATE && !method 1888600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang .equalsIgnoreCase(Request.BYE)) 1889600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang || (this.isServer() && this.getState().getValue() == EARLY_STATE && method 1890600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang .equalsIgnoreCase(Request.BYE))) 1891600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new SipException("Dialog " + getDialogId() 1892600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang + " not yet established or terminated " + this.getState()); 1893600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1894600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SipUri sipUri = null; 1895600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.getRemoteTarget() != null) 1896600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipUri = (SipUri) this.getRemoteTarget().getURI().clone(); 1897600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang else { 1898600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipUri = (SipUri) this.getRemoteParty().getURI().clone(); 1899600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipUri.clearUriParms(); 1900600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1901600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1902600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang CSeq cseq = new CSeq(); 1903600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 1904600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang cseq.setMethod(method); 1905600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang cseq.setSeqNumber(this.getLocalSeqNumber()); 1906600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } catch (Exception ex) { 1907600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) 1908600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logError("Unexpected error"); 1909600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang InternalErrorHandler.handleException(ex); 1910600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1911600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 1912600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Add a via header for the outbound request based on the transport of the message 1913600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * processor. 1914600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1915600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1916600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang ListeningPointImpl lp = (ListeningPointImpl) this.sipProvider 1917600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang .getListeningPoint(sipResponse.getTopmostVia().getTransport()); 1918600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (lp == null) { 1919600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) 1920600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logError( 1921600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang "Cannot find listening point for transport " 1922600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang + sipResponse.getTopmostVia().getTransport()); 1923600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new SipException("Cannot find listening point for transport " 1924600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang + sipResponse.getTopmostVia().getTransport()); 1925600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1926600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang Via via = lp.getViaHeader(); 1927600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1928600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang From from = new From(); 1929600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang from.setAddress(this.localParty); 1930600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang To to = new To(); 1931600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang to.setAddress(this.remoteParty); 1932600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SIPRequest sipRequest = sipResponse.createRequest(sipUri, via, cseq, from, to); 1933600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1934600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 1935600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * The default contact header is obtained from the provider. The application can override 1936600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * this. 1937600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1938600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * JvB: Should only do this for target refresh requests, ie not for BYE, PRACK, etc 1939600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1940600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1941600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (SIPRequest.isTargetRefresh(method)) { 1942600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang ContactHeader contactHeader = ((ListeningPointImpl) this.sipProvider 1943600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang .getListeningPoint(lp.getTransport())).createContactHeader(); 1944600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1945600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang ((SipURI) contactHeader.getAddress().getURI()).setSecure(this.isSecure()); 1946600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipRequest.setHeader(contactHeader); 1947600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1948600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1949600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 1950600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 1951600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Guess of local sequence number - this is being re-set when the request is actually 1952600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * dispatched 1953600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1954600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang cseq = (CSeq) sipRequest.getCSeq(); 1955600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang cseq.setSeqNumber(this.localSequenceNumber + 1); 1956600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1957600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } catch (InvalidArgumentException ex) { 1958600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang InternalErrorHandler.handleException(ex); 1959600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1960600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1961600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (method.equals(Request.SUBSCRIBE)) { 1962600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1963600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (eventHeader != null) 1964600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipRequest.addHeader(eventHeader); 1965600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1966600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1967600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1968600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 1969600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * RFC3261, section 12.2.1.1: 1970600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 1971600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * The URI in the To field of the request MUST be set to the remote URI from the dialog 1972600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * state. The tag in the To header field of the request MUST be set to the remote tag of 1973600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * the dialog ID. The From URI of the request MUST be set to the local URI from the dialog 1974600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * state. The tag in the From header field of the request MUST be set to the local tag of 1975600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * the dialog ID. If the value of the remote or local tags is null, the tag parameter MUST 1976600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * be omitted from the To or From header fields, respectively. 1977600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 1978600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1979600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 1980600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.getLocalTag() != null) { 1981600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang from.setTag(this.getLocalTag()); 1982600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else { 1983600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang from.removeTag(); 1984600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1985600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.getRemoteTag() != null) { 1986600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang to.setTag(this.getRemoteTag()); 1987600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else { 1988600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang to.removeTag(); 1989600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1990600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } catch (ParseException ex) { 1991600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang InternalErrorHandler.handleException(ex); 1992600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 1993600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1994600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // get the route list from the dialog. 1995600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.updateRequest(sipRequest); 1996600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1997600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return sipRequest; 1998600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 1999600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2000600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2001600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 2002600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * (non-Javadoc) 2003600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 2004600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @see javax.sip.Dialog#sendRequest(javax.sip.ClientTransaction) 2005600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 2006600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2007600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public void sendRequest(ClientTransaction clientTransactionId) 2008600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throws TransactionDoesNotExistException, SipException { 2009600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.sendRequest(clientTransactionId, !this.isBackToBackUserAgent); 2010600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2011600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2012600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public void sendRequest(ClientTransaction clientTransactionId, boolean allowInterleaving) 2013600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throws TransactionDoesNotExistException, SipException { 2014600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2015600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if ( (!allowInterleaving) 2016600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang && clientTransactionId.getRequest().getMethod().equals(Request.INVITE)) { 2017600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang new Thread((new ReInviteSender(clientTransactionId))).start(); 2018600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return; 2019600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2020600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2021600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SIPRequest dialogRequest = ((SIPClientTransaction) clientTransactionId) 2022600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang .getOriginalRequest(); 2023600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2024600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) 2025600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug( 2026600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang "dialog.sendRequest " + " dialog = " + this + "\ndialogRequest = \n" 2027600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang + dialogRequest); 2028600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2029600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (clientTransactionId == null) 2030600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new NullPointerException("null parameter"); 2031600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2032600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (dialogRequest.getMethod().equals(Request.ACK) 2033600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang || dialogRequest.getMethod().equals(Request.CANCEL)) 2034600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new SipException("Bad Request Method. " + dialogRequest.getMethod()); 2035600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2036600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // JvB: added, allow re-sending of BYE after challenge 2037600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (byeSent && isTerminatedOnBye() && !dialogRequest.getMethod().equals(Request.BYE)) { 2038600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) 2039600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logError("BYE already sent for " + this); 2040600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new SipException("Cannot send request; BYE already sent"); 2041600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2042600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2043600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (dialogRequest.getTopmostVia() == null) { 2044600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang Via via = ((SIPClientTransaction) clientTransactionId).getOutgoingViaHeader(); 2045600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang dialogRequest.addHeader(via); 2046600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2047600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (!this.getCallId().getCallId().equalsIgnoreCase(dialogRequest.getCallId().getCallId())) { 2048600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2049600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) { 2050600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logError("CallID " + this.getCallId()); 2051600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logError( 2052600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang "RequestCallID = " + dialogRequest.getCallId().getCallId()); 2053600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logError("dialog = " + this); 2054600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2055600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new SipException("Bad call ID in request"); 2056600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2057600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2058600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Set the dialog back pointer. 2059600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang ((SIPClientTransaction) clientTransactionId).setDialog(this, this.dialogId); 2060600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2061600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.addTransaction((SIPTransaction) clientTransactionId); 2062600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Enable the retransmission filter for the transaction 2063600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2064600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang ((SIPClientTransaction) clientTransactionId).isMapped = true; 2065600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2066600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang From from = (From) dialogRequest.getFrom(); 2067600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang To to = (To) dialogRequest.getTo(); 2068600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2069600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Caller already did the tag assignment -- check to see if the 2070600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // tag assignment is OK. 2071600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.getLocalTag() != null && from.getTag() != null 2072600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang && !from.getTag().equals(this.getLocalTag())) 2073600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new SipException("From tag mismatch expecting " + this.getLocalTag()); 2074600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2075600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.getRemoteTag() != null && to.getTag() != null 2076600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang && !to.getTag().equals(this.getRemoteTag())) { 2077600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) 2078600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.sipStack.getStackLogger().logWarning( 2079600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang "To header tag mismatch expecting " + this.getRemoteTag()); 2080600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2081600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 2082600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * The application is sending a NOTIFY before sending the response of the dialog. 2083600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 2084600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.getLocalTag() == null && dialogRequest.getMethod().equals(Request.NOTIFY)) { 2085600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (!this.getMethod().equals(Request.SUBSCRIBE)) 2086600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new SipException("Trying to send NOTIFY without SUBSCRIBE Dialog!"); 2087600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.setLocalTag(from.getTag()); 2088600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2089600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2090600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2091600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 2092600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.getLocalTag() != null) 2093600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang from.setTag(this.getLocalTag()); 2094600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.getRemoteTag() != null) 2095600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang to.setTag(this.getRemoteTag()); 2096600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2097600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } catch (ParseException ex) { 2098600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2099600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang InternalErrorHandler.handleException(ex); 2100600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2101600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2102600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2103600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang Hop hop = ((SIPClientTransaction) clientTransactionId).getNextHop(); 2104600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) { 2105600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug( 2106600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang "Using hop = " + hop.getHost() + " : " + hop.getPort()); 2107600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2108600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2109600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 2110600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang MessageChannel messageChannel = sipStack.createRawMessageChannel(this 2111600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang .getSipProvider().getListeningPoint(hop.getTransport()).getIPAddress(), 2112600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.firstTransactionPort, hop); 2113600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2114600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang MessageChannel oldChannel = ((SIPClientTransaction) 2115600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang clientTransactionId).getMessageChannel(); 2116600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2117600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Remove this from the connection cache if it is in the 2118600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // connection 2119600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // cache and is not yet active. 2120600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang oldChannel.uncache(); 2121600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2122600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Not configured to cache client connections. 2123600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (!sipStack.cacheClientConnections) { 2124600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang oldChannel.useCount--; 2125600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) 2126600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug( 2127600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang "oldChannel: useCount " + oldChannel.useCount); 2128600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2129600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2130600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2131600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (messageChannel == null) { 2132600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 2133600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * At this point the procedures of 8.1.2 and 12.2.1.1 of RFC3261 have been tried 2134600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * but the resulting next hop cannot be resolved (recall that the exception thrown 2135600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * is caught and ignored in SIPStack.createMessageChannel() so we end up here with 2136600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * a null messageChannel instead of the exception handler below). All else 2137600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * failing, try the outbound proxy in accordance with 8.1.2, in particular: This 2138600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * ensures that outbound proxies that do not add Record-Route header field values 2139600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * will drop out of the path of subsequent requests. It allows endpoints that 2140600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * cannot resolve the first Route URI to delegate that task to an outbound proxy. 2141600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 2142600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * if one considers the 'first Route URI' of a request constructed according to 2143600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 12.2.1.1 to be the request URI when the route set is empty. 2144600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 2145600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) 2146600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug( 2147600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang "Null message channel using outbound proxy !"); 2148600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang Hop outboundProxy = sipStack.getRouter(dialogRequest).getOutboundProxy(); 2149600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (outboundProxy == null) 2150600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new SipException("No route found! hop=" + hop); 2151600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang messageChannel = sipStack.createRawMessageChannel(this.getSipProvider() 2152600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang .getListeningPoint(outboundProxy.getTransport()).getIPAddress(), 2153600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.firstTransactionPort, outboundProxy); 2154600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (messageChannel != null) 2155600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang ((SIPClientTransaction) clientTransactionId) 2156600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang .setEncapsulatedChannel(messageChannel); 2157600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else { 2158600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang ((SIPClientTransaction) clientTransactionId) 2159600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang .setEncapsulatedChannel(messageChannel); 2160600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2161600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) { 2162600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug("using message channel " + messageChannel); 2163600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2164600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2165600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2166600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2167600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2168600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (messageChannel != null) messageChannel.useCount++; 2169600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2170600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // See if we need to release the previously mapped channel. 2171600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if ((!sipStack.cacheClientConnections) && oldChannel != null 2172600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang && oldChannel.useCount <= 0) 2173600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang oldChannel.close(); 2174600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } catch (Exception ex) { 2175600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) 2176600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logException(ex); 2177600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new SipException("Could not create message channel", ex); 2178600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2179600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2180600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 2181600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Increment before setting!! 2182600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang localSequenceNumber++; 2183600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang dialogRequest.getCSeq().setSeqNumber(getLocalSeqNumber()); 2184600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } catch (InvalidArgumentException ex) { 2185600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logFatalError(ex.getMessage()); 2186600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2187600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2188600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 2189600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang ((SIPClientTransaction) clientTransactionId).sendMessage(dialogRequest); 2190600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 2191600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Note that if the BYE is rejected then the Dialog should bo back to the ESTABLISHED 2192600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * state so we only set state after successful send. 2193600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 2194600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (dialogRequest.getMethod().equals(Request.BYE)) { 2195600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.byeSent = true; 2196600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 2197600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Dialog goes into TERMINATED state as soon as BYE is sent. ISSUE 182. 2198600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 2199600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (isTerminatedOnBye()) { 2200600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.setState(DialogState._TERMINATED); 2201600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2202600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2203600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } catch (IOException ex) { 2204600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new SipException("error sending message", ex); 2205600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2206600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2207600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2208600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2209600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 2210600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Return yes if the last response is to be retransmitted. 2211600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 2212600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private boolean toRetransmitFinalResponse(int T2) { 2213600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (--retransmissionTicksLeft == 0) { 2214600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (2 * prevRetransmissionTicks <= T2) 2215600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.retransmissionTicksLeft = 2 * prevRetransmissionTicks; 2216600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang else 2217600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.retransmissionTicksLeft = prevRetransmissionTicks; 2218600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.prevRetransmissionTicks = retransmissionTicksLeft; 2219600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return true; 2220600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else 2221600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return false; 2222600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2223600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2224600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2225600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected void setRetransmissionTicks() { 2226600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.retransmissionTicksLeft = 1; 2227600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.prevRetransmissionTicks = 1; 2228600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2229600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2230600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 2231600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Resend the last ack. 2232600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 2233600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public void resendAck() throws SipException { 2234600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Check for null. 2235600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2236600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.getLastAckSent() != null) { 2237600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (getLastAckSent().getHeader(TimeStampHeader.NAME) != null 2238600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang && sipStack.generateTimeStampHeader) { 2239600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang TimeStamp ts = new TimeStamp(); 2240600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 2241600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang ts.setTimeStamp(System.currentTimeMillis()); 2242600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang getLastAckSent().setHeader(ts); 2243600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } catch (InvalidArgumentException e) { 2244600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2245600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2246600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2247600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.sendAck(getLastAckSent(), false); 2248600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2249600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2250600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2251600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2252600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 2253600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Get the method of the request/response that resulted in the creation of the Dialog. 2254600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 2255600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @return -- the method of the dialog. 2256600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 2257600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public String getMethod() { 2258600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Method of the request or response used to create this dialog 2259600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return this.method; 2260600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2261600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2262600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 2263600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Start the dialog timer. 2264600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 2265600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @param transaction 2266600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 2267600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2268600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected void startTimer(SIPServerTransaction transaction) { 2269600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.timerTask != null && timerTask.transaction == transaction) { 2270600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) 2271600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug("Timer already running for " + getDialogId()); 2272600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return; 2273600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2274600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) 2275600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug("Starting dialog timer for " + getDialogId()); 2276600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.ackSeen = false; 2277600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2278600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang acquireTimerTaskSem(); 2279600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 2280600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.timerTask != null) { 2281600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.timerTask.transaction = transaction; 2282600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else { 2283600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.timerTask = new DialogTimerTask(transaction); 2284600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getTimer().schedule(timerTask, SIPTransactionStack.BASE_TIMER_INTERVAL, 2285600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SIPTransactionStack.BASE_TIMER_INTERVAL); 2286600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2287600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } finally { 2288600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang releaseTimerTaskSem(); 2289600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2290600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2291600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.setRetransmissionTicks(); 2292600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2293600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2294600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 2295600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Stop the dialog timer. This is called when the dialog is terminated. 2296600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 2297600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 2298600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected void stopTimer() { 2299600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 2300600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang acquireTimerTaskSem(); 2301600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 2302600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.timerTask != null) { 2303600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.timerTask.cancel(); 2304600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.timerTask = null; 2305600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2306600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } finally { 2307600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang releaseTimerTaskSem(); 2308600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2309600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } catch (Exception ex) { 2310600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2311600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2312600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2313600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 2314600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * (non-Javadoc) Retransmissions of the reliable provisional response cease when a matching 2315600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * PRACK is received by the UA core. PRACK is like any other request within a dialog, and the 2316600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * UAS core processes it according to the procedures of Sections 8.2 and 12.2.2 of RFC 3261. A 2317600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * matching PRACK is defined as one within the same dialog as the response, and whose method, 2318600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * CSeq-num, and response-num in the RAck header field match, respectively, the method from 2319600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * the CSeq, the sequence number from the CSeq, and the sequence number from the RSeq of the 2320600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * reliable provisional response. 2321600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 2322600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @see javax.sip.Dialog#createPrack(javax.sip.message.Response) 2323600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 2324600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public Request createPrack(Response relResponse) throws DialogDoesNotExistException, 2325600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SipException { 2326600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2327600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.getState() == null || this.getState().equals(DialogState.TERMINATED)) 2328600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new DialogDoesNotExistException("Dialog not initialized or terminated"); 2329600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2330600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if ((RSeq) relResponse.getHeader(RSeqHeader.NAME) == null) { 2331600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new SipException("Missing RSeq Header"); 2332600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2333600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2334600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 2335600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SIPResponse sipResponse = (SIPResponse) relResponse; 2336600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SIPRequest sipRequest = (SIPRequest) this.createRequest(Request.PRACK, 2337600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang (SIPResponse) relResponse); 2338600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang String toHeaderTag = sipResponse.getTo().getTag(); 2339600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipRequest.setToTag(toHeaderTag); 2340600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang RAck rack = new RAck(); 2341600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang RSeq rseq = (RSeq) relResponse.getHeader(RSeqHeader.NAME); 2342600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang rack.setMethod(sipResponse.getCSeq().getMethod()); 2343600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang rack.setCSequenceNumber((int) sipResponse.getCSeq().getSeqNumber()); 2344600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang rack.setRSequenceNumber(rseq.getSeqNumber()); 2345600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipRequest.setHeader(rack); 2346600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return (Request) sipRequest; 2347600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } catch (Exception ex) { 2348600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang InternalErrorHandler.handleException(ex); 2349600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return null; 2350600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2351600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2352600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2353600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2354600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private void updateRequest(SIPRequest sipRequest) { 2355600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2356600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang RouteList rl = this.getRouteList(); 2357600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (rl.size() > 0) { 2358600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipRequest.setHeader(rl); 2359600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else { 2360600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipRequest.removeHeader(RouteHeader.NAME); 2361600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2362600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (MessageFactoryImpl.getDefaultUserAgentHeader() != null) { 2363600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipRequest.setHeader(MessageFactoryImpl.getDefaultUserAgentHeader()); 2364600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2365600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2366600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2367600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2368600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 2369600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * (non-Javadoc) The UAC core MUST generate an ACK request for each 2xx received from the 2370600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * transaction layer. The header fields of the ACK are constructed in the same way as for any 2371600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * request sent within a dialog (see Section 12) with the exception of the CSeq and the header 2372600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * fields related to authentication. The sequence number of the CSeq header field MUST be the 2373600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * same as the INVITE being acknowledged, but the CSeq method MUST be ACK. The ACK MUST 2374600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * contain the same credentials as the INVITE. If the 2xx contains an offer (based on the 2375600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * rules above), the ACK MUST carry an answer in its body. If the offer in the 2xx response is 2376600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * not acceptable, the UAC core MUST generate a valid answer in the ACK and then send a BYE 2377600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * immediately. 2378600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 2379600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Note that for the case of forked requests, you can create multiple outgoing invites each 2380600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * with a different cseq and hence you need to supply the invite. 2381600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 2382600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @see javax.sip.Dialog#createAck(long) 2383600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 2384600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public Request createAck(long cseqno) throws InvalidArgumentException, SipException { 2385600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2386600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // JvB: strictly speaking it is allowed to start a dialog with 2387600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // SUBSCRIBE, 2388600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // then send INVITE+ACK later on 2389600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (!method.equals(Request.INVITE)) 2390600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new SipException("Dialog was not created with an INVITE" + method); 2391600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2392600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (cseqno <= 0) 2393600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new InvalidArgumentException("bad cseq <= 0 "); 2394600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang else if (cseqno > ((((long) 1) << 32) - 1)) 2395600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new InvalidArgumentException("bad cseq > " + ((((long) 1) << 32) - 1)); 2396600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2397600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.remoteTarget == null) { 2398600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new SipException("Cannot create ACK - no remote Target!"); 2399600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2400600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2401600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.sipStack.isLoggingEnabled()) { 2402600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.sipStack.getStackLogger().logDebug("createAck " + this + " cseqno " + cseqno); 2403600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2404600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2405600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // MUST ack in the same order that the OKs were received. This traps 2406600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // out of order ACK sending. Old ACKs seqno's can always be ACKed. 2407600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (lastInviteOkReceived < cseqno) { 2408600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) { 2409600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.sipStack.getStackLogger().logDebug( 2410600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang "WARNING : Attempt to crete ACK without OK " + this); 2411600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.sipStack.getStackLogger().logDebug("LAST RESPONSE = " + this.lastResponse); 2412600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2413600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new SipException("Dialog not yet established -- no OK response!"); 2414600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2415600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2416600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 2417600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2418600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // JvB: Transport from first entry in route set, or remote Contact 2419600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // if none 2420600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Only used to find correct LP & create correct Via 2421600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SipURI uri4transport = null; 2422600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2423600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.routeList != null && !this.routeList.isEmpty()) { 2424600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang Route r = (Route) this.routeList.getFirst(); 2425600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang uri4transport = ((SipURI) r.getAddress().getURI()); 2426600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else { // should be !=null, checked above 2427600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang uri4transport = ((SipURI) this.remoteTarget.getURI()); 2428600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2429600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2430600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang String transport = uri4transport.getTransportParam(); 2431600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (transport == null) { 2432600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // JvB fix: also support TLS 2433600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang transport = uri4transport.isSecure() ? ListeningPoint.TLS : ListeningPoint.UDP; 2434600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2435600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang ListeningPointImpl lp = (ListeningPointImpl) sipProvider.getListeningPoint(transport); 2436600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (lp == null) { 2437600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) { 2438600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logError( 2439600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang "remoteTargetURI " + this.remoteTarget.getURI()); 2440600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logError("uri4transport = " + uri4transport); 2441600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logError("No LP found for transport=" + transport); 2442600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2443600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new SipException( 2444600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang "Cannot create ACK - no ListeningPoint for transport towards next hop found:" 2445600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang + transport); 2446600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2447600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SIPRequest sipRequest = new SIPRequest(); 2448600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipRequest.setMethod(Request.ACK); 2449600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipRequest.setRequestURI((SipUri) getRemoteTarget().getURI().clone()); 2450600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipRequest.setCallId(this.callIdHeader); 2451600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipRequest.setCSeq(new CSeq(cseqno, Request.ACK)); 2452600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang List<Via> vias = new ArrayList<Via>(); 2453600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Via via = lp.getViaHeader(); 2454600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // The user may have touched the sentby for the response. 2455600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // so use the via header extracted from the response for the ACK => 2456600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // https://jain-sip.dev.java.net/issues/show_bug.cgi?id=205 2457600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // strip the params from the via of the response and use the params from the 2458600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // original request 2459600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang Via via = this.lastResponse.getTopmostVia(); 2460600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang via.removeParameters(); 2461600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (originalRequest != null && originalRequest.getTopmostVia() != null) { 2462600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang NameValueList originalRequestParameters = originalRequest.getTopmostVia() 2463600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang .getParameters(); 2464600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (originalRequestParameters != null && originalRequestParameters.size() > 0) { 2465600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang via.setParameters((NameValueList) originalRequestParameters.clone()); 2466600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2467600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2468600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang via.setBranch(Utils.getInstance().generateBranchId()); // new branch 2469600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang vias.add(via); 2470600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipRequest.setVia(vias); 2471600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang From from = new From(); 2472600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang from.setAddress(this.localParty); 2473600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang from.setTag(this.myTag); 2474600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipRequest.setFrom(from); 2475600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang To to = new To(); 2476600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang to.setAddress(this.remoteParty); 2477600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (hisTag != null) 2478600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang to.setTag(this.hisTag); 2479600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipRequest.setTo(to); 2480600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipRequest.setMaxForwards(new MaxForwards(70)); 2481600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2482600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.originalRequest != null) { 2483600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang Authorization authorization = this.originalRequest.getAuthorization(); 2484600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (authorization != null) 2485600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipRequest.setHeader(authorization); 2486600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2487600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2488600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // ACKs for 2xx responses 2489600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // use the Route values learned from the Record-Route of the 2xx 2490600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // responses. 2491600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.updateRequest(sipRequest); 2492600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2493600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return sipRequest; 2494600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } catch (Exception ex) { 2495600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang InternalErrorHandler.handleException(ex); 2496600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new SipException("unexpected exception ", ex); 2497600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2498600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2499600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2500600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2501600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 2502600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Get the provider for this Dialog. 2503600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 2504600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * SPEC_REVISION 2505600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 2506600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @return -- the SIP Provider associated with this transaction. 2507600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 2508600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public SipProviderImpl getSipProvider() { 2509600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return this.sipProvider; 2510600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2511600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2512600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 2513600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @param sipProvider the sipProvider to set 2514600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 2515600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public void setSipProvider(SipProviderImpl sipProvider) { 2516600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.sipProvider = sipProvider; 2517600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2518600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2519600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 2520600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Check the tags of the response against the tags of the Dialog. Return true if the respnse 2521600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * matches the tags of the dialog. We do this check wehn sending out a response. 2522600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 2523600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @param sipResponse -- the response to check. 2524600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 2525600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 2526600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public void setResponseTags(SIPResponse sipResponse) { 2527600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.getLocalTag() != null || this.getRemoteTag() != null) { 2528600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return; 2529600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2530600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang String responseFromTag = sipResponse.getFromTag(); 2531600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if ( responseFromTag != null ) { 2532600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (responseFromTag.equals(this.getLocalTag())) { 2533600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipResponse.setToTag(this.getRemoteTag()); 2534600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else if (responseFromTag.equals(this.getRemoteTag())) { 2535600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipResponse.setToTag(this.getLocalTag()); 2536600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2537600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else { 2538600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) 2539600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logWarning("No from tag in response! Not RFC 3261 compatible."); 2540600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2541600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2542600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2543600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2544600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 2545600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Set the last response for this dialog. This method is called for updating the dialog state 2546600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * when a response is either sent or received from within a Dialog. 2547600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 2548600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @param transaction -- the transaction associated with the response 2549600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @param sipResponse -- the last response to set. 2550600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 2551600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public void setLastResponse(SIPTransaction transaction, SIPResponse sipResponse) { 2552600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.callIdHeader = sipResponse.getCallId(); 2553600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang int statusCode = sipResponse.getStatusCode(); 2554600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (statusCode == 100) { 2555600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) 2556600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logWarning( 2557600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang "Invalid status code - 100 in setLastResponse - ignoring"); 2558600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return; 2559600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2560600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2561600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.lastResponse = sipResponse; 2562600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.setAssigned(); 2563600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Adjust state of the Dialog state machine. 2564600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) { 2565600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug( 2566600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang "sipDialog: setLastResponse:" + this + " lastResponse = " 2567600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang + this.lastResponse.getFirstLine()); 2568600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2569600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.getState() == DialogState.TERMINATED) { 2570600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) { 2571600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug( 2572600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang "sipDialog: setLastResponse -- dialog is terminated - ignoring "); 2573600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2574600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Capture the OK response for later use in createAck 2575600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // This is handy for late arriving OK's that we want to ACK. 2576600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipResponse.getCSeq().getMethod().equals(Request.INVITE) && statusCode == 200) { 2577600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2578600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.lastInviteOkReceived = Math.max(sipResponse.getCSeq().getSeqNumber(), 2579600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.lastInviteOkReceived); 2580600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2581600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return; 2582600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2583600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang String cseqMethod = sipResponse.getCSeq().getMethod(); 2584600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) { 2585600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logStackTrace(); 2586600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug("cseqMethod = " + cseqMethod); 2587600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug("dialogState = " + this.getState()); 2588600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug("method = " + this.getMethod()); 2589600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug("statusCode = " + statusCode); 2590600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug("transaction = " + transaction); 2591600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2592600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2593600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // JvB: don't use "!this.isServer" here 2594600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // note that the transaction can be null for forked 2595600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // responses. 2596600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (transaction == null || transaction instanceof ClientTransaction) { 2597600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isDialogCreated(cseqMethod)) { 2598600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Make a final tag assignment. 2599600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (getState() == null && (statusCode / 100 == 1)) { 2600600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 2601600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Guard aginst slipping back into early state from confirmed state. 2602600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 2603600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Was (sipResponse.getToTag() != null || sipStack.rfc2543Supported) 2604600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang setState(SIPDialog.EARLY_STATE); 2605600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if ((sipResponse.getToTag() != null || sipStack.rfc2543Supported) 2606600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang && this.getRemoteTag() == null) { 2607600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang setRemoteTag(sipResponse.getToTag()); 2608600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.setDialogId(sipResponse.getDialogId(false)); 2609600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.putDialog(this); 2610600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.addRoute(sipResponse); 2611600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2612600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else if (getState() != null && getState().equals(DialogState.EARLY) 2613600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang && statusCode / 100 == 1) { 2614600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 2615600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * This case occurs for forked dialog responses. The To tag can change as a 2616600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * result of the forking. The remote target can also change as a result of the 2617600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * forking. 2618600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 2619600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (cseqMethod.equals(getMethod()) && transaction != null 2620600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang && (sipResponse.getToTag() != null || sipStack.rfc2543Supported)) { 2621600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang setRemoteTag(sipResponse.getToTag()); 2622600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.setDialogId(sipResponse.getDialogId(false)); 2623600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.putDialog(this); 2624600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.addRoute(sipResponse); 2625600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2626600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else if (statusCode / 100 == 2) { 2627600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // This is a dialog creating method (such as INVITE). 2628600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // 2xx response -- set the state to the confirmed 2629600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // state. To tag is MANDATORY for the response. 2630600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2631600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Only do this if method equals initial request! 2632600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2633600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (cseqMethod.equals(getMethod()) 2634600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang && (sipResponse.getToTag() != null || sipStack.rfc2543Supported) 2635600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang && this.getState() != DialogState.CONFIRMED) { 2636600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang setRemoteTag(sipResponse.getToTag()); 2637600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.setDialogId(sipResponse.getDialogId(false)); 2638600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.putDialog(this); 2639600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.addRoute(sipResponse); 2640600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2641600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang setState(SIPDialog.CONFIRMED_STATE); 2642600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2643600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2644600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Capture the OK response for later use in createAck 2645600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (cseqMethod.equals(Request.INVITE)) { 2646600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.lastInviteOkReceived = Math.max(sipResponse.getCSeq().getSeqNumber(), 2647600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.lastInviteOkReceived); 2648600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2649600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2650600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else if (statusCode >= 300 2651600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang && statusCode <= 699 2652600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang && (getState() == null || (cseqMethod.equals(getMethod()) && getState() 2653600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang .getValue() == SIPDialog.EARLY_STATE))) { 2654600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 2655600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * This case handles 3xx, 4xx, 5xx and 6xx responses. RFC 3261 Section 12.3 - 2656600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * dialog termination. Independent of the method, if a request outside of a 2657600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * dialog generates a non-2xx final response, any early dialogs created 2658600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * through provisional responses to that request are terminated. 2659600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 2660600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang setState(SIPDialog.TERMINATED_STATE); 2661600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2662600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2663600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 2664600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * This code is in support of "proxy" servers that are constructed as back to back 2665600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * user agents. This could be a dialog in the middle of the call setup path 2666600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * somewhere. Hence the incoming invite has record route headers in it. The 2667600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * response will have additional record route headers. However, for this dialog 2668600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * only the downstream record route headers matter. Ideally proxy servers should 2669600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * not be constructed as Back to Back User Agents. Remove all the record routes 2670600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * that are present in the incoming INVITE so you only have the downstream Route 2671600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * headers present in the dialog. Note that for an endpoint - you will have no 2672600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * record route headers present in the original request so the loop will not 2673600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * execute. 2674600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 2675600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if ( this.getState() != DialogState.CONFIRMED && this.getState() != DialogState.TERMINATED ) { 2676600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (originalRequest != null) { 2677600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang RecordRouteList rrList = originalRequest.getRecordRouteHeaders(); 2678600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (rrList != null) { 2679600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang ListIterator<RecordRoute> it = rrList.listIterator(rrList.size()); 2680600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang while (it.hasPrevious()) { 2681600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang RecordRoute rr = (RecordRoute) it.previous(); 2682600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang Route route = (Route) routeList.getFirst(); 2683600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (route != null && rr.getAddress().equals(route.getAddress())) { 2684600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang routeList.removeFirst(); 2685600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else 2686600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang break; 2687600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2688600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2689600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2690600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2691600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2692600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else if (cseqMethod.equals(Request.NOTIFY) 2693600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang && (this.getMethod().equals(Request.SUBSCRIBE) || this.getMethod().equals( 2694600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang Request.REFER)) && sipResponse.getStatusCode() / 100 == 2 2695600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang && this.getState() == null) { 2696600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // This is a notify response. 2697600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.setDialogId(sipResponse.getDialogId(true)); 2698600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.putDialog(this); 2699600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.setState(SIPDialog.CONFIRMED_STATE); 2700600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2701600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else if (cseqMethod.equals(Request.BYE) && statusCode / 100 == 2 2702600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang && isTerminatedOnBye()) { 2703600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Dialog will be terminated when the transction is terminated. 2704600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang setState(SIPDialog.TERMINATED_STATE); 2705600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2706600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else { 2707600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Processing Server Dialog. 2708600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2709600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (cseqMethod.equals(Request.BYE) && statusCode / 100 == 2 2710600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang && this.isTerminatedOnBye()) { 2711600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 2712600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Only transition to terminated state when 200 OK is returned for the BYE. Other 2713600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * status codes just result in leaving the state in COMPLETED state. 2714600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 2715600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.setState(SIPDialog.TERMINATED_STATE); 2716600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else { 2717600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang boolean doPutDialog = false; 2718600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2719600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (getLocalTag() == null && sipResponse.getTo().getTag() != null 2720600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang && sipStack.isDialogCreated(cseqMethod) && cseqMethod.equals(getMethod())) { 2721600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang setLocalTag(sipResponse.getTo().getTag()); 2722600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2723600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang doPutDialog = true; 2724600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2725600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2726600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (statusCode / 100 != 2) { 2727600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (statusCode / 100 == 1) { 2728600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (doPutDialog) { 2729600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2730600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang setState(SIPDialog.EARLY_STATE); 2731600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.setDialogId(sipResponse.getDialogId(true)); 2732600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.putDialog(this); 2733600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2734600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else { 2735600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 2736600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * RFC 3265 chapter 3.1.4.1 "Non-200 class final responses indicate that 2737600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * no subscription or dialog has been created, and no subsequent NOTIFY 2738600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * message will be sent. All non-200 class" + responses (with the 2739600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * exception of "489", described herein) have the same meanings and 2740600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * handling as described in SIP" 2741600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 2742600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Bug Fix by Jens tinfors 2743600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // see https://jain-sip.dev.java.net/servlets/ReadMsg?list=users&msgNo=797 2744600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (statusCode == 489 2745600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang && (cseqMethod.equals(Request.NOTIFY) || cseqMethod 2746600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang .equals(Request.SUBSCRIBE))) { 2747600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) 2748600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug( 2749600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang "RFC 3265 : Not setting dialog to TERMINATED for 489"); 2750600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else { 2751600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // baranowb: simplest fix to 2752600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // https://jain-sip.dev.java.net/issues/show_bug.cgi?id=175 2753600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // application is responsible for terminating in this case 2754600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // see rfc 5057 for better explanation 2755600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (!this.isReInvite() && getState() != DialogState.CONFIRMED) { 2756600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.setState(SIPDialog.TERMINATED_STATE); 2757600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2758600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2759600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2760600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2761600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else { 2762600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2763600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 2764600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * JvB: RFC4235 says that when sending 2xx on UAS side, state should move to 2765600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * CONFIRMED 2766600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 2767600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.dialogState <= SIPDialog.EARLY_STATE 2768600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang && (cseqMethod.equals(Request.INVITE) 2769600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang || cseqMethod.equals(Request.SUBSCRIBE) || cseqMethod 2770600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang .equals(Request.REFER))) { 2771600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.setState(SIPDialog.CONFIRMED_STATE); 2772600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2773600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2774600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (doPutDialog) { 2775600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.setDialogId(sipResponse.getDialogId(true)); 2776600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.putDialog(this); 2777600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2778600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 2779600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * We put the dialog into the table. We must wait for ACK before re-INVITE is 2780600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * sent 2781600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 2782600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (transaction.getState() != TransactionState.TERMINATED 2783600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang && sipResponse.getStatusCode() == Response.OK 2784600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang && cseqMethod.equals(Request.INVITE) 2785600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang && this.isBackToBackUserAgent) { 2786600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 2787600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Acquire the flag for re-INVITE so that we cannot re-INVITE before 2788600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * ACK is received. 2789600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 2790600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (!this.takeAckSem()) { 2791600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) { 2792600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug( 2793600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang "Delete dialog -- cannot acquire ackSem"); 2794600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2795600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.delete(); 2796600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return; 2797600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2798600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2799600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2800600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2801600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2802600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2803600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2804600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2805600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2806600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2807600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 2808600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Start the retransmit timer. 2809600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 2810600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @param sipServerTx -- server transaction on which the response was sent 2811600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @param response - response that was sent. 2812600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 2813600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public void startRetransmitTimer(SIPServerTransaction sipServerTx, Response response) { 2814600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipServerTx.getRequest().getMethod().equals(Request.INVITE) 2815600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang && response.getStatusCode() / 100 == 2) { 2816600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.startTimer(sipServerTx); 2817600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2818600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2819600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2820600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 2821600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @return -- the last response associated with the dialog. 2822600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 2823600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public SIPResponse getLastResponse() { 2824600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2825600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return lastResponse; 2826600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2827600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2828600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 2829600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Do taget refresh dialog state updates. 2830600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 2831600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * RFC 3261: Requests within a dialog MAY contain Record-Route and Contact header fields. 2832600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * However, these requests do not cause the dialog's route set to be modified, although they 2833600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * may modify the remote target URI. Specifically, requests that are not target refresh 2834600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * requests do not modify the dialog's remote target URI, and requests that are target refresh 2835600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * requests do. For dialogs that have been established with an 2836600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 2837600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * INVITE, the only target refresh request defined is re-INVITE (see Section 14). Other 2838600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * extensions may define different target refresh requests for dialogs established in other 2839600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * ways. 2840600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 2841600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private void doTargetRefresh(SIPMessage sipMessage) { 2842600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2843600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang ContactList contactList = sipMessage.getContactHeaders(); 2844600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2845600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 2846600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * INVITE is the target refresh for INVITE dialogs. SUBSCRIBE is the target refresh for 2847600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * subscribe dialogs from the client side. This modifies the remote target URI potentially 2848600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 2849600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (contactList != null) { 2850600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2851600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang Contact contact = (Contact) contactList.getFirst(); 2852600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.setRemoteTarget(contact); 2853600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2854600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2855600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2856600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2857600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2858600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private static final boolean optionPresent(ListIterator l, String option) { 2859600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang while (l.hasNext()) { 2860600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang OptionTag opt = (OptionTag) l.next(); 2861600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (opt != null && option.equalsIgnoreCase(opt.getOptionTag())) 2862600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return true; 2863600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2864600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return false; 2865600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2866600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2867600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 2868600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * (non-Javadoc) 2869600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 2870600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @see javax.sip.Dialog#createReliableProvisionalResponse(int) 2871600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 2872600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public Response createReliableProvisionalResponse(int statusCode) 2873600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throws InvalidArgumentException, SipException { 2874600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2875600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (!(firstTransactionIsServerTransaction)) { 2876600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new SipException("Not a Server Dialog!"); 2877600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2878600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2879600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 2880600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * A UAS MUST NOT attempt to send a 100 (Trying) response reliably. Only provisional 2881600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * responses numbered 101 to 199 may be sent reliably. If the request did not include 2882600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * either a Supported or Require header field indicating this feature, the UAS MUST NOT 2883600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * send the provisional response reliably. 2884600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 2885600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (statusCode <= 100 || statusCode > 199) 2886600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new InvalidArgumentException("Bad status code "); 2887600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SIPRequest request = this.originalRequest; 2888600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (!request.getMethod().equals(Request.INVITE)) 2889600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new SipException("Bad method"); 2890600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2891600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang ListIterator<SIPHeader> list = request.getHeaders(SupportedHeader.NAME); 2892600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (list == null || !optionPresent(list, "100rel")) { 2893600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang list = request.getHeaders(RequireHeader.NAME); 2894600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (list == null || !optionPresent(list, "100rel")) { 2895600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new SipException("No Supported/Require 100rel header in the request"); 2896600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2897600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2898600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2899600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SIPResponse response = request.createResponse(statusCode); 2900600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 2901600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * The provisional response to be sent reliably is constructed by the UAS core according 2902600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * to the procedures of Section 8.2.6 of RFC 3261. In addition, it MUST contain a Require 2903600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * header field containing the option tag 100rel, and MUST include an RSeq header field. 2904600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * The value of the header field for the first reliable provisional response in a 2905600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * transaction MUST be between 1 and 2**31 - 1. It is RECOMMENDED that it be chosen 2906600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * uniformly in this range. The RSeq numbering space is within a single transaction. This 2907600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * means that provisional responses for different requests MAY use the same values for the 2908600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * RSeq number. 2909600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 2910600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang Require require = new Require(); 2911600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 2912600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang require.setOptionTag("100rel"); 2913600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } catch (Exception ex) { 2914600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang InternalErrorHandler.handleException(ex); 2915600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2916600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang response.addHeader(require); 2917600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang RSeq rseq = new RSeq(); 2918600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 2919600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * set an arbitrary sequence number. This is actually set when the response is sent out 2920600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 2921600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang rseq.setSeqNumber(1L); 2922600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 2923600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Copy the record route headers from the request to the response ( Issue 160 ). Note that 2924600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * other 1xx headers do not get their Record Route headers copied over but reliable 2925600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * provisional responses do. See RFC 3262 Table 2. 2926600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 2927600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang RecordRouteList rrl = request.getRecordRouteHeaders(); 2928600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (rrl != null) { 2929600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang RecordRouteList rrlclone = (RecordRouteList) rrl.clone(); 2930600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang response.setHeader(rrlclone); 2931600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2932600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2933600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return response; 2934600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2935600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2936600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 2937600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Do the processing necessary for the PRACK 2938600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 2939600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @param prackRequest 2940600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @return true if this is the first time the tx has seen the prack ( and hence needs to be 2941600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * passed up to the TU) 2942600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 2943600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public boolean handlePrack(SIPRequest prackRequest) { 2944600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 2945600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * The RAck header is sent in a PRACK request to support reliability of provisional 2946600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * responses. It contains two numbers and a method tag. The first number is the value from 2947600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * the RSeq header in the provisional response that is being acknowledged. The next 2948600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * number, and the method, are copied from the CSeq in the response that is being 2949600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * acknowledged. The method name in the RAck header is case sensitive. 2950600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 2951600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (!this.isServer()) { 2952600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) 2953600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug("Dropping Prack -- not a server Dialog"); 2954600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return false; 2955600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2956600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SIPServerTransaction sipServerTransaction = (SIPServerTransaction) this 2957600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang .getFirstTransaction(); 2958600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SIPResponse sipResponse = sipServerTransaction.getReliableProvisionalResponse(); 2959600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2960600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipResponse == null) { 2961600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) 2962600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger() 2963600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang .logDebug("Dropping Prack -- ReliableResponse not found"); 2964600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return false; 2965600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2966600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2967600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang RAck rack = (RAck) prackRequest.getHeader(RAckHeader.NAME); 2968600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2969600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (rack == null) { 2970600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) 2971600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug("Dropping Prack -- rack header not found"); 2972600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return false; 2973600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2974600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang CSeq cseq = (CSeq) sipResponse.getCSeq(); 2975600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2976600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (!rack.getMethod().equals(cseq.getMethod())) { 2977600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) 2978600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug( 2979600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang "Dropping Prack -- CSeq Header does not match PRACK"); 2980600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return false; 2981600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2982600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2983600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (rack.getCSeqNumberLong() != cseq.getSeqNumber()) { 2984600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) 2985600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug( 2986600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang "Dropping Prack -- CSeq Header does not match PRACK"); 2987600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return false; 2988600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2989600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2990600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang RSeq rseq = (RSeq) sipResponse.getHeader(RSeqHeader.NAME); 2991600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2992600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (rack.getRSequenceNumber() != rseq.getSeqNumber()) { 2993600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) 2994600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug( 2995600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang "Dropping Prack -- RSeq Header does not match PRACK"); 2996600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return false; 2997600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 2998600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 2999600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return sipServerTransaction.prackRecieved(); 3000600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3001600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3002600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 3003600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * (non-Javadoc) 3004600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 3005600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @see javax.sip.Dialog#sendReliableProvisionalResponse(javax.sip.message.Response) 3006600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 3007600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public void sendReliableProvisionalResponse(Response relResponse) throws SipException { 3008600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (!this.isServer()) { 3009600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new SipException("Not a Server Dialog"); 3010600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3011600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3012600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SIPResponse sipResponse = (SIPResponse) relResponse; 3013600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3014600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (relResponse.getStatusCode() == 100) 3015600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new SipException("Cannot send 100 as a reliable provisional response"); 3016600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3017600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (relResponse.getStatusCode() / 100 > 2) 3018600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new SipException( 3019600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang "Response code is not a 1xx response - should be in the range 101 to 199 "); 3020600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3021600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 3022600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Do a little checking on the outgoing response. 3023600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 3024600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipResponse.getToTag() == null) { 3025600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new SipException( 3026600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang "Badly formatted response -- To tag mandatory for Reliable Provisional Response"); 3027600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3028600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang ListIterator requireList = (ListIterator) relResponse.getHeaders(RequireHeader.NAME); 3029600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang boolean found = false; 3030600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3031600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (requireList != null) { 3032600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3033600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang while (requireList.hasNext() && !found) { 3034600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang RequireHeader rh = (RequireHeader) requireList.next(); 3035600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (rh.getOptionTag().equalsIgnoreCase("100rel")) { 3036600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang found = true; 3037600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3038600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3039600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3040600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3041600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (!found) { 3042600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang Require require = new Require("100rel"); 3043600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang relResponse.addHeader(require); 3044600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) { 3045600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug( 3046600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang "Require header with optionTag 100rel is needed -- adding one"); 3047600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3048600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3049600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3050600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3051600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SIPServerTransaction serverTransaction = (SIPServerTransaction) this 3052600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang .getFirstTransaction(); 3053600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 3054600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * put into the dialog table before sending the response so as to avoid race condition 3055600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * with PRACK 3056600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 3057600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.setLastResponse(serverTransaction, sipResponse); 3058600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3059600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.setDialogId(sipResponse.getDialogId(true)); 3060600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3061600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang serverTransaction.sendReliableProvisionalResponse(relResponse); 3062600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3063600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.startRetransmitTimer(serverTransaction, relResponse); 3064600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3065600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3066600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3067600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 3068600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * (non-Javadoc) 3069600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 3070600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @see javax.sip.Dialog#terminateOnBye(boolean) 3071600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 3072600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public void terminateOnBye(boolean terminateFlag) throws SipException { 3073600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3074600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.terminateOnBye = terminateFlag; 3075600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3076600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3077600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 3078600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Set the "assigned" flag to true. We do this when inserting the dialog into the dialog table 3079600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * of the stack. 3080600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 3081600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 3082600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public void setAssigned() { 3083600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.isAssigned = true; 3084600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3085600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3086600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 3087600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Return true if the dialog has already been mapped to a transaction. 3088600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 3089600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 3090600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3091600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public boolean isAssigned() { 3092600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return this.isAssigned; 3093600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3094600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3095600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 3096600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Get the contact header that the owner of this dialog assigned. Subsequent Requests are 3097600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * considered to belong to the dialog if the dialog identifier matches and the contact header 3098600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * matches the ip address and port on which the request is received. 3099600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 3100600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @return contact header belonging to the dialog. 3101600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 3102600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public Contact getMyContactHeader() { 3103600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return contactHeader; 3104600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3105600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3106600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 3107600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Do the necessary processing to handle an ACK directed at this Dialog. 3108600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 3109600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @param ackTransaction -- the ACK transaction that was directed at this dialog. 3110600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @return -- true if the ACK was successfully consumed by the Dialog and resulted in the 3111600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * dialog state being changed. 3112600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 3113600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public boolean handleAck(SIPServerTransaction ackTransaction) { 3114600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SIPRequest sipRequest = ackTransaction.getOriginalRequest(); 3115600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3116600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (isAckSeen() && getRemoteSeqNumber() == sipRequest.getCSeq().getSeqNumber()) { 3117600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3118600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) { 3119600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug( 3120600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang "ACK already seen by dialog -- dropping Ack" + " retransmission"); 3121600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3122600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang acquireTimerTaskSem(); 3123600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 3124600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.timerTask != null) { 3125600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.timerTask.cancel(); 3126600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.timerTask = null; 3127600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3128600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } finally { 3129600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang releaseTimerTaskSem(); 3130600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3131600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return false; 3132600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else if (this.getState() == DialogState.TERMINATED) { 3133600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) 3134600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug("Dialog is terminated -- dropping ACK"); 3135600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return false; 3136600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3137600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else { 3138600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3139600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 3140600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * This could be a re-invite processing. check to see if the ack matches with the last 3141600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * transaction. s 3142600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 3143600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3144600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SIPServerTransaction tr = getInviteTransaction(); 3145600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3146600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SIPResponse sipResponse = (tr != null ? tr.getLastResponse() : null); 3147600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3148600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Idiot check for sending ACK from the wrong side! 3149600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (tr != null 3150600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang && sipResponse != null 3151600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang && sipResponse.getStatusCode() / 100 == 2 3152600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang && sipResponse.getCSeq().getMethod().equals(Request.INVITE) 3153600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang && sipResponse.getCSeq().getSeqNumber() == sipRequest.getCSeq() 3154600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang .getSeqNumber()) { 3155600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3156600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang ackTransaction.setDialog(this, sipResponse.getDialogId(false)); 3157600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 3158600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * record that we already saw an ACK for this dialog. 3159600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 3160600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3161600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang ackReceived(sipRequest); 3162600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) 3163600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug("ACK for 2XX response --- sending to TU "); 3164600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return true; 3165600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3166600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else { 3167600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 3168600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * This happens when the ACK is re-transmitted and arrives too late to be 3169600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * processed. 3170600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 3171600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3172600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) 3173600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug( 3174600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang " INVITE transaction not found -- Discarding ACK"); 3175600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return false; 3176600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3177600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3178600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3179600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3180600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang void setEarlyDialogId(String earlyDialogId) { 3181600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.earlyDialogId = earlyDialogId; 3182600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3183600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3184600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang String getEarlyDialogId() { 3185600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return earlyDialogId; 3186600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3187600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3188600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 3189600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Release the semaphore for ACK processing so the next re-INVITE may proceed. 3190600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 3191600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang void releaseAckSem() { 3192600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.isBackToBackUserAgent) { 3193600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) { 3194600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug("releaseAckSem]" + this); 3195600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3196600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.ackSem.release(); 3197600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3198600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3199600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3200600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3201600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang boolean takeAckSem() { 3202600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) { 3203600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug("[takeAckSem " + this); 3204600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3205600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 3206600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (!this.ackSem.tryAcquire(2, TimeUnit.SECONDS)) { 3207600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.isLoggingEnabled()) { 3208600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logError("Cannot aquire ACK semaphore"); 3209600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3210600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3211600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if ( sipStack.isLoggingEnabled() ) { 3212600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logDebug("Semaphore previously acquired at " + this.stackTrace); 3213600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logStackTrace(); 3214600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3215600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3216600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return false; 3217600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3218600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3219600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if ( sipStack.isLoggingEnabled() ) { 3220600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3221600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.recordStackTrace(); 3222600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3223600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3224600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } catch (InterruptedException ex) { 3225600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getStackLogger().logError("Cannot aquire ACK semaphore"); 3226600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return false; 3227600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3228600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3229600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return true; 3230600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3231600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3232600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3233600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 3234600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @param lastAckReceived the lastAckReceived to set 3235600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 3236600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private void setLastAckReceived(SIPRequest lastAckReceived) { 3237600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.lastAckReceived = lastAckReceived; 3238600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3239600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3240600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 3241600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @return the lastAckReceived 3242600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 3243600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected SIPRequest getLastAckReceived() { 3244600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return lastAckReceived; 3245600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3246600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3247600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 3248600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @param lastAckSent the lastAckSent to set 3249600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 3250600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private void setLastAckSent(SIPRequest lastAckSent) { 3251600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.lastAckSent = lastAckSent; 3252600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3253600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3254600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 3255600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @return true if an ack was ever sent for this Dialog 3256600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 3257600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public boolean isAtleastOneAckSent() { 3258600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return this.isAcknowledged; 3259600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3260600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3261600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3262600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3263600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public boolean isBackToBackUserAgent() { 3264600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return this.isBackToBackUserAgent; 3265600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3266600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3267600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public synchronized void doDeferredDeleteIfNoAckSent(long seqno) { 3268600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (sipStack.getTimer() == null) { 3269600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.setState(TERMINATED_STATE); 3270600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else if(dialogDeleteIfNoAckSentTask == null){ 3271600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Delete the transaction after the max ack timeout. 3272600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang dialogDeleteIfNoAckSentTask = new DialogDeleteIfNoAckSentTask(seqno); 3273600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipStack.getTimer().schedule( 3274600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang dialogDeleteIfNoAckSentTask, 3275600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SIPTransaction.TIMER_J 3276600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * SIPTransactionStack.BASE_TIMER_INTERVAL); 3277600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3278600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3279600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3280600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /* 3281600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * (non-Javadoc) 3282600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @see gov.nist.javax.sip.DialogExt#setBackToBackUserAgent(boolean) 3283600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 3284600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public void setBackToBackUserAgent() { 3285600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.isBackToBackUserAgent = true; 3286600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3287600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3288600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 3289600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @return the eventHeader 3290600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 3291600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang EventHeader getEventHeader() { 3292600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return eventHeader; 3293600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3294600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3295600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 3296600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @param eventHeader the eventHeader to set 3297600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 3298600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang void setEventHeader(EventHeader eventHeader) { 3299600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.eventHeader = eventHeader; 3300600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3301600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3302600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 3303600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @param serverTransactionFlag the serverTransactionFlag to set 3304600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 3305600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang void setServerTransactionFlag(boolean serverTransactionFlag) { 3306600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.serverTransactionFlag = serverTransactionFlag; 3307600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3308600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3309600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 3310600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @param reInviteFlag the reinviteFlag to set 3311600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 3312600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang void setReInviteFlag(boolean reInviteFlag) { 3313600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.reInviteFlag = reInviteFlag; 3314600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3315600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3316600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3317600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public boolean isSequnceNumberValidation() { 3318600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return this.sequenceNumberValidation; 3319600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3320600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3321600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public void disableSequenceNumberValidation() { 3322600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.sequenceNumberValidation = false; 3323600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3324600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3325600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3326600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public void acquireTimerTaskSem() { 3327600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang boolean acquired = false; 3328600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 3329600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang acquired = this.timerTaskLock.tryAcquire(10, TimeUnit.SECONDS); 3330600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } catch ( InterruptedException ex) { 3331600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang acquired = false; 3332600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3333600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if(!acquired) { 3334600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new IllegalStateException("Impossible to acquire the dialog timer task lock"); 3335600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3336600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3337600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3338600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public void releaseTimerTaskSem() { 3339600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.timerTaskLock.release(); 3340600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 3341600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3342600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 3343600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang} 3344