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