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 Wangpackage gov.nist.javax.sip.stack;
27600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
28600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.core.InternalErrorHandler;
29600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.core.NameValueList;
30600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.SIPConstants;
31600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.Utils;
32600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.address.AddressImpl;
33600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.Contact;
34600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.RecordRoute;
35600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.RecordRouteList;
36600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.Route;
37600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.RouteList;
38600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.TimeStamp;
39600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.To;
40600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.Via;
41600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.ViaList;
42600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.message.SIPMessage;
43600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.message.SIPRequest;
44600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.message.SIPResponse;
45600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
46600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.io.IOException;
47600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.security.cert.X509Certificate;
48600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.text.ParseException;
49600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.util.ListIterator;
50600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.util.TimerTask;
51600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.util.concurrent.ConcurrentHashMap;
52600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
53600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.net.ssl.SSLPeerUnverifiedException;
54600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.Dialog;
55600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.DialogState;
56600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.InvalidArgumentException;
57600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.ObjectInUseException;
58600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.SipException;
59600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.Timeout;
60600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.TimeoutEvent;
61600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.TransactionState;
62600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.address.Hop;
63600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.address.SipURI;
64600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.header.ExpiresHeader;
65600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.header.RouteHeader;
66600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.header.TimeStampHeader;
67600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.message.Request;
68600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
69600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/*
70600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Jeff Keyser -- initial. Daniel J. Martinez Manzano --Added support for TLS message channel.
71600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Emil Ivov -- bug fixes. Chris Beardshear -- bug fix. Andreas Bystrom -- bug fixes. Matt Keller
72600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * (Motorolla) -- bug fix.
73600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */
74600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
75600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/**
76600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Represents a client transaction. Implements the following state machines. (From RFC 3261)
77600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
78600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * <pre>
79600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
80600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
81600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
82600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
83600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
84600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
85600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                                     |INVITE from TU
86600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                   Timer A fires     |INVITE sent
87600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                   Reset A,          V                      Timer B fires
88600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                   INVITE sent +-----------+                or Transport Err.
89600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                     +---------|           |---------------+inform TU
90600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                     |         |  Calling  |               |
91600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                     +--------&gt;|           |--------------&gt;|
92600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                               +-----------+ 2xx           |
93600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                                  |  |       2xx to TU     |
94600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                                  |  |1xx                  |
95600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                          300-699 +---------------+  |1xx to TU            |
96600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                         ACK sent |                  |                     |
97600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                      resp. to TU |  1xx             V                     |
98600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                  |  1xx to TU  -----------+               |
99600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                  |  +---------|           |               |
100600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                  |  |         |Proceeding |--------------&gt;|
101600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                  |  +--------&gt;|           | 2xx           |
102600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                  |            +-----------+ 2xx to TU     |
103600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                  |       300-699    |                     |
104600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                  |       ACK sent,  |                     |
105600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                  |       resp. to TU|                     |
106600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                  |                  |                     |      NOTE:
107600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                  |  300-699         V                     |
108600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                  |  ACK sent  +-----------+Transport Err. |  transitions
109600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                  |  +---------|           |Inform TU      |  labeled with
110600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                  |  |         | Completed |--------------&gt;|  the event
111600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                  |  +--------&gt;|           |               |  over the action
112600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                  |            +-----------+               |  to take
113600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                  |              &circ;   |                     |
114600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                  |              |   | Timer D fires       |
115600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                  +--------------+   | -                   |
116600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                                     |                     |
117600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                                     V                     |
118600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                               +-----------+               |
119600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                               |           |               |
120600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                               | Terminated|&lt;--------------+
121600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                               |           |
122600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                               +-----------+
123600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
124600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                       Figure 5: INVITE client transaction
125600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
126600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
127600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                                         |Request from TU
128600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                                         |send request
129600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                     Timer E             V
130600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                     send request  +-----------+
131600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                         +---------|           |-------------------+
132600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                         |         |  Trying   |  Timer F          |
133600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                         +--------&gt;|           |  or Transport Err.|
134600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                                   +-----------+  inform TU        |
135600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                      200-699         |  |                         |
136600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                      resp. to TU     |  |1xx                      |
137600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                      +---------------+  |resp. to TU              |
138600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                      |                  |                         |
139600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                      |   Timer E        V       Timer F           |
140600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                      |   send req +-----------+ or Transport Err. |
141600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                      |  +---------|           | inform TU         |
142600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                      |  |         |Proceeding |------------------&gt;|
143600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                      |  +--------&gt;|           |-----+             |
144600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                      |            +-----------+     |1xx          |
145600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                      |              |      &circ;        |resp to TU   |
146600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                      | 200-699      |      +--------+             |
147600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                      | resp. to TU  |                             |
148600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                      |              |                             |
149600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                      |              V                             |
150600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                      |            +-----------+                   |
151600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                      |            |           |                   |
152600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                      |            | Completed |                   |
153600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                      |            |           |                   |
154600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                      |            +-----------+                   |
155600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                      |              &circ;   |                         |
156600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                      |              |   | Timer K                 |
157600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                      +--------------+   | -                       |
158600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                                         |                         |
159600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                                         V                         |
160600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                   NOTE:           +-----------+                   |
161600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                                   |           |                   |
162600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                               transitions         | Terminated|&lt;------------------+
163600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                               labeled with        |           |
164600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                               the event           +-----------+
165600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                               over the action
166600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                               to take
167600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
168600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *                                       Figure 6: non-INVITE client transaction
169600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
170600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
171600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
172600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
173600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
174600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
175600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * </pre>
176600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
177600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
178600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @author M. Ranganathan
179600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
180600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @version 1.2 $Revision: 1.122 $ $Date: 2009/12/17 23:33:52 $
181600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */
182600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangpublic class SIPClientTransaction extends SIPTransaction implements ServerResponseInterface,
183600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        javax.sip.ClientTransaction, gov.nist.javax.sip.ClientTransactionExt {
184600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
185600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // a SIP Client transaction may belong simultaneously to multiple
186600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // dialogs in the early state. These dialogs all have
187600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // the same call ID and same From tag but different to tags.
188600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
189600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private ConcurrentHashMap<String,SIPDialog> sipDialogs;
190600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
191600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private SIPRequest lastRequest;
192600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
193600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private int viaPort;
194600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
195600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private String viaHost;
196600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
197600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // Real ResponseInterface to pass messages to
198600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private transient ServerResponseInterface respondTo;
199600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
200600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private SIPDialog defaultDialog;
201600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
202600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private Hop nextHop;
203600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
204600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private boolean notifyOnRetransmit;
205600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
206600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private boolean timeoutIfStillInCallingState;
207600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
208600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private int callingStateTimeoutCount;
209600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
210600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public class TransactionTimer extends SIPStackTimerTask {
211600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
212600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        public TransactionTimer() {
213600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
214600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
215600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
216600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        protected void runTask() {
217600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            SIPClientTransaction clientTransaction;
218600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            SIPTransactionStack sipStack;
219600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            clientTransaction = SIPClientTransaction.this;
220600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            sipStack = clientTransaction.sipStack;
221600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
222600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // If the transaction has terminated,
223600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (clientTransaction.isTerminated()) {
224600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
225600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (sipStack.isLoggingEnabled()) {
226600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    sipStack.getStackLogger().logDebug(
227600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            "removing  = " + clientTransaction + " isReliable "
228600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                    + clientTransaction.isReliable());
229600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
230600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
231600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                sipStack.removeTransaction(clientTransaction);
232600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
233600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                try {
234600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    this.cancel();
235600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
236600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } catch (IllegalStateException ex) {
237600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (!sipStack.isAlive())
238600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        return;
239600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
240600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
241600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Client transaction terminated. Kill connection if
242600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // this is a TCP after the linger timer has expired.
243600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // The linger timer is needed to allow any pending requests to
244600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // return responses.
245600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if ((!sipStack.cacheClientConnections) && clientTransaction.isReliable()) {
246600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
247600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    int newUseCount = --clientTransaction.getMessageChannel().useCount;
248600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (newUseCount <= 0) {
249600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        // Let the connection linger for a while and then close
250600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        // it.
251600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        TimerTask myTimer = new LingerTimer();
252600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        sipStack.getTimer().schedule(myTimer,
253600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                SIPTransactionStack.CONNECTION_LINGER_TIME * 1000);
254600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
255600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
256600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } else {
257600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // Cache the client connections so dont close the
258600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // connection. This keeps the connection open permanently
259600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // until the client disconnects.
260600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (sipStack.isLoggingEnabled() && clientTransaction.isReliable()) {
261600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                       	int useCount = clientTransaction.getMessageChannel().useCount;
262600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                       	if (sipStack.isLoggingEnabled())
263600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                       		sipStack.getStackLogger().logDebug("Client Use Count = " + useCount);
264600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
265600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
266600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
267600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } else {
268600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // If this transaction has not
269600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // terminated,
270600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Fire the transaction timer.
271600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                clientTransaction.fireTimer();
272600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
273600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
274600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
275600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
276600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
277600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
278600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
279600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
280600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Creates a new client transaction.
281600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
282600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param newSIPStack Transaction stack this transaction belongs to.
283600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param newChannelToUse Channel to encapsulate.
284600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return the created client transaction.
285600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
286600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected SIPClientTransaction(SIPTransactionStack newSIPStack, MessageChannel newChannelToUse) {
287600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        super(newSIPStack, newChannelToUse);
288600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Create a random branch parameter for this transaction
289600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // setBranch( SIPConstants.BRANCH_MAGIC_COOKIE +
290600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Integer.toHexString( hashCode( ) ) );
291600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        setBranch(Utils.getInstance().generateBranchId());
292600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.messageProcessor = newChannelToUse.messageProcessor;
293600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.setEncapsulatedChannel(newChannelToUse);
294600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.notifyOnRetransmit = false;
295600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.timeoutIfStillInCallingState = false;
296600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
297600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // This semaphore guards the listener from being
298600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // re-entered for this transaction. That is
299600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // for a give tx, the listener is called at most
300600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // once with an outstanding request.
301600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
302600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (sipStack.isLoggingEnabled()) {
303600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            sipStack.getStackLogger().logDebug("Creating clientTransaction " + this);
304600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            sipStack.getStackLogger().logStackTrace();
305600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
306600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // this.startTransactionTimer();
307600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.sipDialogs = new ConcurrentHashMap();
308600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
309600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
310600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
311600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Sets the real ResponseInterface this transaction encapsulates.
312600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
313600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param newRespondTo ResponseInterface to send messages to.
314600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
315600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void setResponseInterface(ServerResponseInterface newRespondTo) {
316600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (sipStack.isLoggingEnabled()) {
317600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            sipStack.getStackLogger().logDebug(
318600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    "Setting response interface for " + this + " to " + newRespondTo);
319600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (newRespondTo == null) {
320600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                sipStack.getStackLogger().logStackTrace();
321600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                sipStack.getStackLogger().logDebug("WARNING -- setting to null!");
322600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
323600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
324600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
325600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        respondTo = newRespondTo;
326600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
327600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
328600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
329600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
330600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Returns this transaction.
331600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
332600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public MessageChannel getRequestChannel() {
333600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
334600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return this;
335600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
336600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
337600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
338600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
339600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Deterines if the message is a part of this transaction.
340600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
341600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param messageToTest Message to check if it is part of this transaction.
342600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
343600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return true if the message is part of this transaction, false if not.
344600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
345600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public boolean isMessagePartOfTransaction(SIPMessage messageToTest) {
346600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
347600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // List of Via headers in the message to test
348600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        ViaList viaHeaders = messageToTest.getViaHeaders();
349600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Flags whether the select message is part of this transaction
350600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        boolean transactionMatches;
351600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String messageBranch = ((Via) viaHeaders.getFirst()).getBranch();
352600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        boolean rfc3261Compliant = getBranch() != null
353600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                && messageBranch != null
354600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                && getBranch().toLowerCase().startsWith(
355600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        SIPConstants.BRANCH_MAGIC_COOKIE_LOWER_CASE)
356600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                && messageBranch.toLowerCase().startsWith(
357600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        SIPConstants.BRANCH_MAGIC_COOKIE_LOWER_CASE);
358600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
359600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        transactionMatches = false;
360600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (TransactionState.COMPLETED == this.getState()) {
361600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (rfc3261Compliant) {
362600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                transactionMatches = getBranch().equalsIgnoreCase(
363600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        ((Via) viaHeaders.getFirst()).getBranch())
364600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        && getMethod().equals(messageToTest.getCSeq().getMethod());
365600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } else {
366600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                transactionMatches = getBranch().equals(messageToTest.getTransactionId());
367600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
368600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else if (!isTerminated()) {
369600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (rfc3261Compliant) {
370600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (viaHeaders != null) {
371600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // If the branch parameter is the
372600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // same as this transaction and the method is the same,
373600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (getBranch().equalsIgnoreCase(((Via) viaHeaders.getFirst()).getBranch())) {
374600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        transactionMatches = getOriginalRequest().getCSeq().getMethod().equals(
375600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                messageToTest.getCSeq().getMethod());
376600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
377600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
378600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
379600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } else {
380600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // not RFC 3261 compliant.
381600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (getBranch() != null) {
382600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    transactionMatches = getBranch().equalsIgnoreCase(
383600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            messageToTest.getTransactionId());
384600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } else {
385600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    transactionMatches = getOriginalRequest().getTransactionId()
386600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            .equalsIgnoreCase(messageToTest.getTransactionId());
387600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
388600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
389600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
390600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
391600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
392600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return transactionMatches;
393600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
394600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
395600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
396600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
397600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Send a request message through this transaction and onto the client.
398600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
399600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param messageToSend Request to process and send.
400600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
401600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void sendMessage(SIPMessage messageToSend) throws IOException {
402600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
403600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        try {
404600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Message typecast as a request
405600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            SIPRequest transactionRequest;
406600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
407600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            transactionRequest = (SIPRequest) messageToSend;
408600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
409600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Set the branch id for the top via header.
410600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            Via topVia = (Via) transactionRequest.getViaHeaders().getFirst();
411600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Tack on a branch identifier to match responses.
412600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            try {
413600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                topVia.setBranch(getBranch());
414600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } catch (java.text.ParseException ex) {
415600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
416600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
417600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (sipStack.isLoggingEnabled()) {
418600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                sipStack.getStackLogger().logDebug("Sending Message " + messageToSend);
419600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                sipStack.getStackLogger().logDebug("TransactionState " + this.getState());
420600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
421600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // If this is the first request for this transaction,
422600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (TransactionState.PROCEEDING == getState()
423600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    || TransactionState.CALLING == getState()) {
424600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
425600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // If this is a TU-generated ACK request,
426600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (transactionRequest.getMethod().equals(Request.ACK)) {
427600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
428600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // Send directly to the underlying
429600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // transport and close this transaction
430600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (isReliable()) {
431600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        this.setState(TransactionState.TERMINATED);
432600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    } else {
433600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        this.setState(TransactionState.COMPLETED);
434600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
435600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // BUGBUG -- This suppresses sending the ACK uncomment this
436600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // to
437600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // test 4xx retransmission
438600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // if (transactionRequest.getMethod() != Request.ACK)
439600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    super.sendMessage(transactionRequest);
440600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    return;
441600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
442600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
443600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
444600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
445600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            try {
446600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
447600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Send the message to the server
448600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                lastRequest = transactionRequest;
449600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (getState() == null) {
450600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // Save this request as the one this transaction
451600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // is handling
452600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    setOriginalRequest(transactionRequest);
453600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // Change to trying/calling state
454600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // Set state first to avoid race condition..
455600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
456600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (transactionRequest.getMethod().equals(Request.INVITE)) {
457600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        this.setState(TransactionState.CALLING);
458600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    } else if (transactionRequest.getMethod().equals(Request.ACK)) {
459600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        // Acks are never retransmitted.
460600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        this.setState(TransactionState.TERMINATED);
461600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    } else {
462600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        this.setState(TransactionState.TRYING);
463600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
464600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (!isReliable()) {
465600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        enableRetransmissionTimer();
466600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
467600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (isInviteTransaction()) {
468600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        enableTimeoutTimer(TIMER_B);
469600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    } else {
470600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        enableTimeoutTimer(TIMER_F);
471600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
472600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
473600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // BUGBUG This supresses sending ACKS -- uncomment to test
474600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // 4xx retransmission.
475600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // if (transactionRequest.getMethod() != Request.ACK)
476600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                super.sendMessage(transactionRequest);
477600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
478600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } catch (IOException e) {
479600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
480600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                this.setState(TransactionState.TERMINATED);
481600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                throw e;
482600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
483600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
484600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } finally {
485600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.isMapped = true;
486600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.startTransactionTimer();
487600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
488600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
489600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
490600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
491600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
492600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
493600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Process a new response message through this transaction. If necessary, this message will
494600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * also be passed onto the TU.
495600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
496600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param transactionResponse Response to process.
497600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param sourceChannel Channel that received this message.
498600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
499600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public synchronized void processResponse(SIPResponse transactionResponse,
500600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            MessageChannel sourceChannel, SIPDialog dialog) {
501600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
502600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // If the state has not yet been assigned then this is a
503600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // spurious response.
504600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
505600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (getState() == null)
506600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return;
507600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
508600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Ignore 1xx
509600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if ((TransactionState.COMPLETED == this.getState() || TransactionState.TERMINATED == this
510600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                .getState())
511600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                && transactionResponse.getStatusCode() / 100 == 1) {
512600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return;
513600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
514600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
515600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (sipStack.isLoggingEnabled()) {
516600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            sipStack.getStackLogger().logDebug(
517600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    "processing " + transactionResponse.getFirstLine() + "current state = "
518600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            + getState());
519600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            sipStack.getStackLogger().logDebug("dialog = " + dialog);
520600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
521600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
522600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.lastResponse = transactionResponse;
523600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
524600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        /*
525600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * JvB: this is now duplicate with code in the other processResponse
526600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         *
527600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * if (dialog != null && transactionResponse.getStatusCode() != 100 &&
528600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * (transactionResponse.getTo().getTag() != null || sipStack .isRfc2543Supported())) { //
529600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * add the route before you process the response. dialog.setLastResponse(this,
530600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * transactionResponse); this.setDialog(dialog, transactionResponse.getDialogId(false)); }
531600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         */
532600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
533600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        try {
534600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (isInviteTransaction())
535600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                inviteClientTransaction(transactionResponse, sourceChannel, dialog);
536600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            else
537600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                nonInviteClientTransaction(transactionResponse, sourceChannel, dialog);
538600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } catch (IOException ex) {
539600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (sipStack.isLoggingEnabled())
540600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                sipStack.getStackLogger().logException(ex);
541600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.setState(TransactionState.TERMINATED);
542600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            raiseErrorEvent(SIPTransactionErrorEvent.TRANSPORT_ERROR);
543600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
544600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
545600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
546600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
547600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Implements the state machine for invite client transactions.
548600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
549600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * <pre>
550600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
551600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
552600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
553600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
554600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
555600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                                         |Request from TU
556600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                                         |send request
557600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                     Timer E             V
558600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                     send request  +-----------+
559600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                         +---------|           |-------------------+
560600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                         |         |  Trying   |  Timer F          |
561600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                         +--------&gt;|           |  or Transport Err.|
562600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                                   +-----------+  inform TU        |
563600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                      200-699         |  |                         |
564600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                      resp. to TU     |  |1xx                      |
565600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                      +---------------+  |resp. to TU              |
566600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                      |                  |                         |
567600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                      |   Timer E        V       Timer F           |
568600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                      |   send req +-----------+ or Transport Err. |
569600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                      |  +---------|           | inform TU         |
570600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                      |  |         |Proceeding |------------------&gt;|
571600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                      |  +--------&gt;|           |-----+             |
572600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                      |            +-----------+     |1xx          |
573600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                      |              |      &circ;        |resp to TU   |
574600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                      | 200-699      |      +--------+             |
575600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                      | resp. to TU  |                             |
576600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                      |              |                             |
577600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                      |              V                             |
578600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                      |            +-----------+                   |
579600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                      |            |           |                   |
580600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                      |            | Completed |                   |
581600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                      |            |           |                   |
582600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                      |            +-----------+                   |
583600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                      |              &circ;   |                         |
584600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                      |              |   | Timer K                 |
585600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                      +--------------+   | -                       |
586600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                                         |                         |
587600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                                         V                         |
588600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                   NOTE:           +-----------+                   |
589600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                                   |           |                   |
590600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                               transitions         | Terminated|&lt;------------------+
591600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                               labeled with        |           |
592600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                               the event           +-----------+
593600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                               over the action
594600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                               to take
595600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
596600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                       Figure 6: non-INVITE client transaction
597600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
598600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
599600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
600600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
601600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * </pre>
602600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
603600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param transactionResponse -- transaction response received.
604600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param sourceChannel - source channel on which the response was received.
605600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
606600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private void nonInviteClientTransaction(SIPResponse transactionResponse,
607600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            MessageChannel sourceChannel, SIPDialog sipDialog) throws IOException {
608600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        int statusCode = transactionResponse.getStatusCode();
609600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (TransactionState.TRYING == this.getState()) {
610600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (statusCode / 100 == 1) {
611600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                this.setState(TransactionState.PROCEEDING);
612600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                enableRetransmissionTimer(MAXIMUM_RETRANSMISSION_TICK_COUNT);
613600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                enableTimeoutTimer(TIMER_F);
614600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // According to RFC, the TU has to be informed on
615600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // this transition.
616600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (respondTo != null) {
617600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    respondTo.processResponse(transactionResponse, this, sipDialog);
618600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } else {
619600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    this.semRelease();
620600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
621600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } else if (200 <= statusCode && statusCode <= 699) {
622600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Send the response up to the TU.
623600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (respondTo != null) {
624600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    respondTo.processResponse(transactionResponse, this, sipDialog);
625600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } else {
626600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    this.semRelease();
627600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
628600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (!isReliable()) {
629600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    this.setState(TransactionState.COMPLETED);
630600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    enableTimeoutTimer(TIMER_K);
631600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } else {
632600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    this.setState(TransactionState.TERMINATED);
633600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
634600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
635600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else if (TransactionState.PROCEEDING == this.getState()) {
636600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (statusCode / 100 == 1) {
637600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (respondTo != null) {
638600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    respondTo.processResponse(transactionResponse, this, sipDialog);
639600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } else {
640600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    this.semRelease();
641600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
642600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } else if (200 <= statusCode && statusCode <= 699) {
643600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (respondTo != null) {
644600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    respondTo.processResponse(transactionResponse, this, sipDialog);
645600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } else {
646600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    this.semRelease();
647600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
648600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                disableRetransmissionTimer();
649600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                disableTimeoutTimer();
650600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (!isReliable()) {
651600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    this.setState(TransactionState.COMPLETED);
652600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    enableTimeoutTimer(TIMER_K);
653600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } else {
654600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    this.setState(TransactionState.TERMINATED);
655600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
656600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
657600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else {
658600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (sipStack.isLoggingEnabled()) {
659600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                sipStack.getStackLogger().logDebug(
660600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        " Not sending response to TU! " + getState());
661600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
662600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.semRelease();
663600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
664600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
665600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
666600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
667600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Implements the state machine for invite client transactions.
668600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
669600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * <pre>
670600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
671600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
672600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
673600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
674600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
675600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                                     |INVITE from TU
676600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                   Timer A fires     |INVITE sent
677600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                   Reset A,          V                      Timer B fires
678600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                   INVITE sent +-----------+                or Transport Err.
679600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                     +---------|           |---------------+inform TU
680600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                     |         |  Calling  |               |
681600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                     +--------&gt;|           |--------------&gt;|
682600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                               +-----------+ 2xx           |
683600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                                  |  |       2xx to TU     |
684600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                                  |  |1xx                  |
685600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                          300-699 +---------------+  |1xx to TU            |
686600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                         ACK sent |                  |                     |
687600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                      resp. to TU |  1xx             V                     |
688600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                  |  1xx to TU  -----------+               |
689600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                  |  +---------|           |               |
690600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                  |  |         |Proceeding |--------------&gt;|
691600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                  |  +--------&gt;|           | 2xx           |
692600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                  |            +-----------+ 2xx to TU     |
693600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                  |       300-699    |                     |
694600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                  |       ACK sent,  |                     |
695600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                  |       resp. to TU|                     |
696600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                  |                  |                     |      NOTE:
697600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                  |  300-699         V                     |
698600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                  |  ACK sent  +-----------+Transport Err. |  transitions
699600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                  |  +---------|           |Inform TU      |  labeled with
700600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                  |  |         | Completed |--------------&gt;|  the event
701600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                  |  +--------&gt;|           |               |  over the action
702600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                  |            +-----------+               |  to take
703600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                  |              &circ;   |                     |
704600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                  |              |   | Timer D fires       |
705600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                  +--------------+   | -                   |
706600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                                     |                     |
707600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                                     V                     |
708600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                               +-----------+               |
709600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                               |           |               |
710600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                               | Terminated|&lt;--------------+
711600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                               |           |
712600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                                               +-----------+
713600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
714600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
715600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
716600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
717600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * </pre>
718600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
719600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param transactionResponse -- transaction response received.
720600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param sourceChannel - source channel on which the response was received.
721600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
722600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
723600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private void inviteClientTransaction(SIPResponse transactionResponse,
724600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            MessageChannel sourceChannel, SIPDialog dialog) throws IOException {
725600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        int statusCode = transactionResponse.getStatusCode();
726600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
727600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (TransactionState.TERMINATED == this.getState()) {
728600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            boolean ackAlreadySent = false;
729600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (dialog != null && dialog.isAckSeen() && dialog.getLastAckSent() != null) {
730600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (dialog.getLastAckSent().getCSeq().getSeqNumber() == transactionResponse.getCSeq()
731600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        .getSeqNumber()
732600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        && transactionResponse.getFromTag().equals(
733600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                dialog.getLastAckSent().getFromTag())) {
734600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // the last ack sent corresponded to this response
735600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    ackAlreadySent = true;
736600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
737600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
738600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // retransmit the ACK for this response.
739600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (dialog!= null && ackAlreadySent
740600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    && transactionResponse.getCSeq().getMethod().equals(dialog.getMethod())) {
741600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                try {
742600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // Found the dialog - resend the ACK and
743600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // dont pass up the null transaction
744600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (sipStack.isLoggingEnabled())
745600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        sipStack.getStackLogger().logDebug("resending ACK");
746600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
747600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    dialog.resendAck();
748600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } catch (SipException ex) {
749600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // What to do here ?? kill the dialog?
750600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
751600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
752600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
753600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.semRelease();
754600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return;
755600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else if (TransactionState.CALLING == this.getState()) {
756600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (statusCode / 100 == 2) {
757600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
758600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // JvB: do this ~before~ calling the application, to avoid
759600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // retransmissions
760600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // of the INVITE after app sends ACK
761600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                disableRetransmissionTimer();
762600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                disableTimeoutTimer();
763600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                this.setState(TransactionState.TERMINATED);
764600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
765600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // 200 responses are always seen by TU.
766600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (respondTo != null)
767600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    respondTo.processResponse(transactionResponse, this, dialog);
768600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                else {
769600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    this.semRelease();
770600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
771600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
772600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } else if (statusCode / 100 == 1) {
773600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                disableRetransmissionTimer();
774600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                disableTimeoutTimer();
775600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                this.setState(TransactionState.PROCEEDING);
776600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
777600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (respondTo != null)
778600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    respondTo.processResponse(transactionResponse, this, dialog);
779600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                else {
780600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    this.semRelease();
781600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
782600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
783600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } else if (300 <= statusCode && statusCode <= 699) {
784600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Send back an ACK request
785600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
786600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                try {
787600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    sendMessage((SIPRequest) createErrorAck());
788600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
789600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } catch (Exception ex) {
790600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    sipStack.getStackLogger().logError(
791600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            "Unexpected Exception sending ACK -- sending error AcK ", ex);
792600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
793600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
794600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
795600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                /*
796600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                 * When in either the "Calling" or "Proceeding" states, reception of response with
797600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                 * status code from 300-699 MUST cause the client transaction to transition to
798600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                 * "Completed". The client transaction MUST pass the received response up to the
799600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                 * TU, and the client transaction MUST generate an ACK request.
800600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                 */
801600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
802600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (respondTo != null) {
803600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    respondTo.processResponse(transactionResponse, this, dialog);
804600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } else {
805600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    this.semRelease();
806600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
807600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
808600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (this.getDialog() != null &&  ((SIPDialog)this.getDialog()).isBackToBackUserAgent()) {
809600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    ((SIPDialog) this.getDialog()).releaseAckSem();
810600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
811600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
812600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (!isReliable()) {
813600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    this.setState(TransactionState.COMPLETED);
814600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    enableTimeoutTimer(TIMER_D);
815600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } else {
816600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // Proceed immediately to the TERMINATED state.
817600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    this.setState(TransactionState.TERMINATED);
818600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
819600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
820600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else if (TransactionState.PROCEEDING == this.getState()) {
821600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (statusCode / 100 == 1) {
822600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (respondTo != null) {
823600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    respondTo.processResponse(transactionResponse, this, dialog);
824600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } else {
825600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    this.semRelease();
826600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
827600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } else if (statusCode / 100 == 2) {
828600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                this.setState(TransactionState.TERMINATED);
829600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (respondTo != null) {
830600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    respondTo.processResponse(transactionResponse, this, dialog);
831600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } else {
832600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    this.semRelease();
833600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
834600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
835600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } else if (300 <= statusCode && statusCode <= 699) {
836600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Send back an ACK request
837600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                try {
838600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    sendMessage((SIPRequest) createErrorAck());
839600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } catch (Exception ex) {
840600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    InternalErrorHandler.handleException(ex);
841600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
842600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
843600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (this.getDialog() != null) {
844600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    ((SIPDialog) this.getDialog()).releaseAckSem();
845600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
846600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // JvB: update state before passing to app
847600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (!isReliable()) {
848600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    this.setState(TransactionState.COMPLETED);
849600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    this.enableTimeoutTimer(TIMER_D);
850600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } else {
851600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    this.setState(TransactionState.TERMINATED);
852600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
853600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
854600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Pass up to the TU for processing.
855600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (respondTo != null)
856600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    respondTo.processResponse(transactionResponse, this, dialog);
857600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                else {
858600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    this.semRelease();
859600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
860600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
861600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // JvB: duplicate with line 874
862600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // if (!isReliable()) {
863600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // enableTimeoutTimer(TIMER_D);
864600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // }
865600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
866600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else if (TransactionState.COMPLETED == this.getState()) {
867600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (300 <= statusCode && statusCode <= 699) {
868600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Send back an ACK request
869600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                try {
870600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    sendMessage((SIPRequest) createErrorAck());
871600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } catch (Exception ex) {
872600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    InternalErrorHandler.handleException(ex);
873600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } finally {
874600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    this.semRelease();
875600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
876600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
877600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
878600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
879600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
880600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
881600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
882600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
883600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * (non-Javadoc)
884600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
885600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @see javax.sip.ClientTransaction#sendRequest()
886600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
887600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void sendRequest() throws SipException {
888600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        SIPRequest sipRequest = this.getOriginalRequest();
889600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
890600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (this.getState() != null)
891600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw new SipException("Request already sent");
892600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
893600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (sipStack.isLoggingEnabled()) {
894600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            sipStack.getStackLogger().logDebug("sendRequest() " + sipRequest);
895600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
896600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
897600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        try {
898600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            sipRequest.checkHeaders();
899600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } catch (ParseException ex) {
900600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        	if (sipStack.isLoggingEnabled())
901600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        		sipStack.getStackLogger().logError("missing required header");
902600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw new SipException(ex.getMessage());
903600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
904600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
905600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (getMethod().equals(Request.SUBSCRIBE)
906600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                && sipRequest.getHeader(ExpiresHeader.NAME) == null) {
907600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            /*
908600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang             * If no "Expires" header is present in a SUBSCRIBE request, the implied default is
909600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang             * defined by the event package being used.
910600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang             *
911600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang             */
912600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        	if (sipStack.isLoggingEnabled())
913600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        		sipStack.getStackLogger().logWarning(
914600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    "Expires header missing in outgoing subscribe --"
915600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            + " Notifier will assume implied value on event package");
916600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
917600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        try {
918600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            /*
919600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang             * This check is removed because it causes problems for load balancers ( See issue
920600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang             * 136) reported by Raghav Ramesh ( BT )
921600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang             *
922600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang             */
923600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (this.getOriginalRequest().getMethod().equals(Request.CANCEL)
924600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    && sipStack.isCancelClientTransactionChecked()) {
925600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                SIPClientTransaction ct = (SIPClientTransaction) sipStack.findCancelTransaction(
926600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        this.getOriginalRequest(), false);
927600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (ct == null) {
928600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    /*
929600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                     * If the original request has generated a final response, the CANCEL SHOULD
930600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                     * NOT be sent, as it is an effective no-op, since CANCEL has no effect on
931600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                     * requests that have already generated a final response.
932600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                     */
933600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    throw new SipException("Could not find original tx to cancel. RFC 3261 9.1");
934600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } else if (ct.getState() == null) {
935600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    throw new SipException(
936600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            "State is null no provisional response yet -- cannot cancel RFC 3261 9.1");
937600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } else if (!ct.getMethod().equals(Request.INVITE)) {
938600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    throw new SipException("Cannot cancel non-invite requests RFC 3261 9.1");
939600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
940600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } else
941600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
942600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (this.getOriginalRequest().getMethod().equals(Request.BYE)
943600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    || this.getOriginalRequest().getMethod().equals(Request.NOTIFY)) {
944600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                SIPDialog dialog = sipStack.getDialog(this.getOriginalRequest()
945600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        .getDialogId(false));
946600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // I want to behave like a user agent so send the BYE using the
947600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Dialog
948600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (this.getSipProvider().isAutomaticDialogSupportEnabled() && dialog != null) {
949600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    throw new SipException(
950600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            "Dialog is present and AutomaticDialogSupport is enabled for "
951600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                    + " the provider -- Send the Request using the Dialog.sendRequest(transaction)");
952600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
953600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
954600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Only map this after the fist request is sent out.
955600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (this.getMethod().equals(Request.INVITE)) {
956600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                SIPDialog dialog = this.getDefaultDialog();
957600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
958600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (dialog != null && dialog.isBackToBackUserAgent()) {
959600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // Block sending re-INVITE till we see the ACK.
960600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if ( ! dialog.takeAckSem() ) {
961600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        throw new SipException ("Failed to take ACK semaphore");
962600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
963600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
964600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
965600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
966600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.isMapped = true;
967600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.sendMessage(sipRequest);
968600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
969600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } catch (IOException ex) {
970600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.setState(TransactionState.TERMINATED);
971600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw new SipException("IO Error sending request", ex);
972600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
973600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
974600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
975600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
976600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
977600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
978600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Called by the transaction stack when a retransmission timer fires.
979600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
980600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected void fireRetransmissionTimer() {
981600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
982600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        try {
983600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
984600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Resend the last request sent
985600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (this.getState() == null || !this.isMapped)
986600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                return;
987600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
988600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            boolean inv = isInviteTransaction();
989600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            TransactionState s = this.getState();
990600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
991600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // JvB: INVITE CTs only retransmit in CALLING, non-INVITE in both TRYING and
992600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // PROCEEDING
993600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Bug-fix for non-INVITE transactions not retransmitted when 1xx response received
994600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if ((inv && TransactionState.CALLING == s)
995600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    || (!inv && (TransactionState.TRYING == s || TransactionState.PROCEEDING == s))) {
996600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // If the retransmission filter is disabled then
997600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // retransmission of the INVITE is the application
998600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // responsibility.
999600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1000600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (lastRequest != null) {
1001600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (sipStack.generateTimeStampHeader
1002600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            && lastRequest.getHeader(TimeStampHeader.NAME) != null) {
1003600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        long milisec = System.currentTimeMillis();
1004600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        TimeStamp timeStamp = new TimeStamp();
1005600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        try {
1006600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            timeStamp.setTimeStamp(milisec);
1007600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        } catch (InvalidArgumentException ex) {
1008600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            InternalErrorHandler.handleException(ex);
1009600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        }
1010600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        lastRequest.setHeader(timeStamp);
1011600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
1012600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    super.sendMessage(lastRequest);
1013600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (this.notifyOnRetransmit) {
1014600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        TimeoutEvent txTimeout = new TimeoutEvent(this.getSipProvider(), this,
1015600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                Timeout.RETRANSMIT);
1016600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        this.getSipProvider().handleEvent(txTimeout, this);
1017600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
1018600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (this.timeoutIfStillInCallingState
1019600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            && this.getState() == TransactionState.CALLING) {
1020600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        this.callingStateTimeoutCount--;
1021600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        if (callingStateTimeoutCount == 0) {
1022600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            TimeoutEvent timeoutEvent = new TimeoutEvent(this.getSipProvider(),
1023600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                    this, Timeout.RETRANSMIT);
1024600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            this.getSipProvider().handleEvent(timeoutEvent, this);
1025600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            this.timeoutIfStillInCallingState = false;
1026600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        }
1027600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1028600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
1029600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
1030600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1031600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
1032600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } catch (IOException e) {
1033600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.raiseIOExceptionEvent();
1034600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            raiseErrorEvent(SIPTransactionErrorEvent.TRANSPORT_ERROR);
1035600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1036600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1037600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1038600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1039600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1040600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Called by the transaction stack when a timeout timer fires.
1041600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1042600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected void fireTimeoutTimer() {
1043600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1044600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (sipStack.isLoggingEnabled())
1045600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            sipStack.getStackLogger().logDebug("fireTimeoutTimer " + this);
1046600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1047600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        SIPDialog dialog = (SIPDialog) this.getDialog();
1048600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (TransactionState.CALLING == this.getState()
1049600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                || TransactionState.TRYING == this.getState()
1050600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                || TransactionState.PROCEEDING == this.getState()) {
1051600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Timeout occured. If this is asociated with a transaction
1052600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // creation then kill the dialog.
1053600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (dialog != null
1054600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    && (dialog.getState() == null || dialog.getState() == DialogState.EARLY)) {
1055600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (((SIPTransactionStack) getSIPStack()).isDialogCreated(this
1056600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        .getOriginalRequest().getMethod())) {
1057600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // If this is a re-invite we do not delete the dialog even
1058600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // if the
1059600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // reinvite times out. Else
1060600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // terminate the enclosing dialog.
1061600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    dialog.delete();
1062600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
1063600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } else if (dialog != null) {
1064600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Guard against the case of BYE time out.
1065600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1066600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (getOriginalRequest().getMethod().equalsIgnoreCase(Request.BYE)
1067600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        && dialog.isTerminatedOnBye()) {
1068600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // Terminate the associated dialog on BYE Timeout.
1069600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    dialog.delete();
1070600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
1071600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
1072600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1073600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (TransactionState.COMPLETED != this.getState()) {
1074600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            raiseErrorEvent(SIPTransactionErrorEvent.TIMEOUT_ERROR);
1075600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Got a timeout error on a cancel.
1076600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (this.getOriginalRequest().getMethod().equalsIgnoreCase(Request.CANCEL)) {
1077600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                SIPClientTransaction inviteTx = (SIPClientTransaction) this.getOriginalRequest()
1078600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        .getInviteTransaction();
1079600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (inviteTx != null
1080600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        && ((inviteTx.getState() == TransactionState.CALLING || inviteTx
1081600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                .getState() == TransactionState.PROCEEDING))
1082600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        && inviteTx.getDialog() != null) {
1083600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    /*
1084600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                     * A proxy server should have started TIMER C and take care of the Termination
1085600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                     * using transaction.terminate() by itself (i.e. this is not the job of the
1086600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                     * stack at this point but we do it to be nice.
1087600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                     */
1088600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    inviteTx.setState(TransactionState.TERMINATED);
1089600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1090600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
1091600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
1092600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1093600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else {
1094600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.setState(TransactionState.TERMINATED);
1095600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1096600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1097600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1098600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1099600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
1100600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * (non-Javadoc)
1101600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1102600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @see javax.sip.ClientTransaction#createCancel()
1103600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1104600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public Request createCancel() throws SipException {
1105600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        SIPRequest originalRequest = this.getOriginalRequest();
1106600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (originalRequest == null)
1107600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw new SipException("Bad state " + getState());
1108600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (!originalRequest.getMethod().equals(Request.INVITE))
1109600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw new SipException("Only INIVTE may be cancelled");
1110600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1111600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (originalRequest.getMethod().equalsIgnoreCase(Request.ACK))
1112600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw new SipException("Cannot Cancel ACK!");
1113600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        else {
1114600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            SIPRequest cancelRequest = originalRequest.createCancelRequest();
1115600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            cancelRequest.setInviteTransaction(this);
1116600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return cancelRequest;
1117600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1118600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1119600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1120600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
1121600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * (non-Javadoc)
1122600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1123600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @see javax.sip.ClientTransaction#createAck()
1124600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1125600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public Request createAck() throws SipException {
1126600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        SIPRequest originalRequest = this.getOriginalRequest();
1127600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (originalRequest == null)
1128600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw new SipException("bad state " + getState());
1129600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (getMethod().equalsIgnoreCase(Request.ACK)) {
1130600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw new SipException("Cannot ACK an ACK!");
1131600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else if (lastResponse == null) {
1132600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw new SipException("bad Transaction state");
1133600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else if (lastResponse.getStatusCode() < 200) {
1134600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (sipStack.isLoggingEnabled()) {
1135600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                sipStack.getStackLogger().logDebug("lastResponse = " + lastResponse);
1136600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
1137600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw new SipException("Cannot ACK a provisional response!");
1138600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1139600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        SIPRequest ackRequest = originalRequest.createAckRequest((To) lastResponse.getTo());
1140600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Pull the record route headers from the last reesponse.
1141600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        RecordRouteList recordRouteList = lastResponse.getRecordRouteHeaders();
1142600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (recordRouteList == null) {
1143600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // If the record route list is null then we can
1144600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // construct the ACK from the specified contact header.
1145600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Note the 3xx check here because 3xx is a redirect.
1146600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // The contact header for the 3xx is the redirected
1147600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // location so we cannot use that to construct the
1148600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // request URI.
1149600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (lastResponse.getContactHeaders() != null
1150600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    && lastResponse.getStatusCode() / 100 != 3) {
1151600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                Contact contact = (Contact) lastResponse.getContactHeaders().getFirst();
1152600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                javax.sip.address.URI uri = (javax.sip.address.URI) contact.getAddress().getURI()
1153600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        .clone();
1154600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                ackRequest.setRequestURI(uri);
1155600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
1156600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return ackRequest;
1157600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1158600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1159600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        ackRequest.removeHeader(RouteHeader.NAME);
1160600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        RouteList routeList = new RouteList();
1161600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // start at the end of the list and walk backwards
1162600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        ListIterator<RecordRoute> li = recordRouteList.listIterator(recordRouteList.size());
1163600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        while (li.hasPrevious()) {
1164600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            RecordRoute rr = (RecordRoute) li.previous();
1165600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1166600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            Route route = new Route();
1167600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            route.setAddress((AddressImpl) ((AddressImpl) rr.getAddress()).clone());
1168600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            route.setParameters((NameValueList) rr.getParameters().clone());
1169600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            routeList.add(route);
1170600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1171600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1172600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        Contact contact = null;
1173600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (lastResponse.getContactHeaders() != null) {
1174600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            contact = (Contact) lastResponse.getContactHeaders().getFirst();
1175600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1176600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1177600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (!((SipURI) ((Route) routeList.getFirst()).getAddress().getURI()).hasLrParam()) {
1178600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1179600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Contact may not yet be there (bug reported by Andreas B).
1180600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1181600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            Route route = null;
1182600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (contact != null) {
1183600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                route = new Route();
1184600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                route.setAddress((AddressImpl) ((AddressImpl) (contact.getAddress())).clone());
1185600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
1186600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1187600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            Route firstRoute = (Route) routeList.getFirst();
1188600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            routeList.removeFirst();
1189600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            javax.sip.address.URI uri = firstRoute.getAddress().getURI();
1190600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            ackRequest.setRequestURI(uri);
1191600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1192600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (route != null)
1193600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                routeList.add(route);
1194600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1195600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            ackRequest.addHeader(routeList);
1196600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else {
1197600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (contact != null) {
1198600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                javax.sip.address.URI uri = (javax.sip.address.URI) contact.getAddress().getURI()
1199600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        .clone();
1200600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                ackRequest.setRequestURI(uri);
1201600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                ackRequest.addHeader(routeList);
1202600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
1203600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1204600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return ackRequest;
1205600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1206600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1207600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1208600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
1209600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Creates an ACK for an error response, according to RFC3261 section 17.1.1.3
1210600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1211600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Note that this is different from an ACK for 2xx
1212600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1213600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private final Request createErrorAck() throws SipException, ParseException {
1214600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        SIPRequest originalRequest = this.getOriginalRequest();
1215600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (originalRequest == null)
1216600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw new SipException("bad state " + getState());
1217600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (!getMethod().equals(Request.INVITE)) {
1218600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw new SipException("Can only ACK an INVITE!");
1219600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else if (lastResponse == null) {
1220600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw new SipException("bad Transaction state");
1221600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else if (lastResponse.getStatusCode() < 200) {
1222600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (sipStack.isLoggingEnabled()) {
1223600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                sipStack.getStackLogger().logDebug("lastResponse = " + lastResponse);
1224600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
1225600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw new SipException("Cannot ACK a provisional response!");
1226600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1227600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return originalRequest.createErrorAck((To) lastResponse.getTo());
1228600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1229600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1230600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1231600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Set the port of the recipient.
1232600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1233600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected void setViaPort(int port) {
1234600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.viaPort = port;
1235600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1236600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1237600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1238600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Set the port of the recipient.
1239600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1240600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected void setViaHost(String host) {
1241600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.viaHost = host;
1242600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1243600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1244600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1245600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get the port of the recipient.
1246600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1247600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public int getViaPort() {
1248600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return this.viaPort;
1249600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1250600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1251600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1252600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get the host of the recipient.
1253600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1254600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public String getViaHost() {
1255600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return this.viaHost;
1256600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1257600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1258600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1259600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * get the via header for an outgoing request.
1260600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1261600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public Via getOutgoingViaHeader() {
1262600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return this.getMessageProcessor().getViaHeader();
1263600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1264600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1265600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1266600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * This is called by the stack after a non-invite client transaction goes to completed state.
1267600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1268600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void clearState() {
1269600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // reduce the state to minimum
1270600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // This assumes that the application will not need
1271600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // to access the request once the transaction is
1272600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // completed.
1273600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // TODO -- revisit this - results in a null pointer
1274600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // occuring occasionally.
1275600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // this.lastRequest = null;
1276600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // this.originalRequest = null;
1277600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // this.lastResponse = null;
1278600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1279600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1280600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1281600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Sets a timeout after which the connection is closed (provided the server does not use the
1282600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * connection for outgoing requests in this time period) and calls the superclass to set
1283600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * state.
1284600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1285600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void setState(TransactionState newState) {
1286600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Set this timer for connection caching
1287600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // of incoming connections.
1288600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (newState == TransactionState.TERMINATED && this.isReliable()
1289600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                && (!getSIPStack().cacheClientConnections)) {
1290600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Set a time after which the connection
1291600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // is closed.
1292600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.collectionTime = TIMER_J;
1293600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1294600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1295600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (super.getState() != TransactionState.COMPLETED
1296600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                && (newState == TransactionState.COMPLETED || newState == TransactionState.TERMINATED)) {
1297600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            sipStack.decrementActiveClientTransactionCount();
1298600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1299600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        super.setState(newState);
1300600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1301600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1302600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1303600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Start the timer task.
1304600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1305600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected  void startTransactionTimer() {
1306600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (this.transactionTimerStarted.compareAndSet(false, true)) {
1307600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang	        TimerTask myTimer = new TransactionTimer();
1308600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang	        if ( sipStack.getTimer() != null ) {
1309600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang	            sipStack.getTimer().schedule(myTimer, BASE_TIMER_INTERVAL, BASE_TIMER_INTERVAL);
1310600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang	        }
1311600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1312600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1313600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1314600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
1315600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Terminate a transaction. This marks the tx as terminated The tx scanner will run and remove
1316600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * the tx. (non-Javadoc)
1317600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1318600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @see javax.sip.Transaction#terminate()
1319600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1320600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void terminate() throws ObjectInUseException {
1321600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.setState(TransactionState.TERMINATED);
1322600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1323600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1324600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1325600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1326600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Check if the From tag of the response matches the from tag of the original message. A
1327600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Response with a tag mismatch should be dropped if a Dialog has been created for the
1328600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * original request.
1329600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1330600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param sipResponse the response to check.
1331600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return true if the check passes.
1332600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1333600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public boolean checkFromTag(SIPResponse sipResponse) {
1334600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String originalFromTag = ((SIPRequest) this.getRequest()).getFromTag();
1335600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (this.defaultDialog != null) {
1336600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (originalFromTag == null ^ sipResponse.getFrom().getTag() == null) {
1337600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            	if (sipStack.isLoggingEnabled())
1338600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            		sipStack.getStackLogger().logDebug("From tag mismatch -- dropping response");
1339600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                return false;
1340600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
1341600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (originalFromTag != null
1342600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    && !originalFromTag.equalsIgnoreCase(sipResponse.getFrom().getTag())) {
1343600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            	if (sipStack.isLoggingEnabled())
1344600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            		sipStack.getStackLogger().logDebug("From tag mismatch -- dropping response");
1345600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                return false;
1346600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
1347600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1348600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return true;
1349600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1350600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1351600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1352600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
1353600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * (non-Javadoc)
1354600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1355600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @see gov.nist.javax.sip.stack.ServerResponseInterface#processResponse(gov.nist.javax.sip.message.SIPResponse,
1356600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *      gov.nist.javax.sip.stack.MessageChannel)
1357600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1358600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void processResponse(SIPResponse sipResponse, MessageChannel incomingChannel) {
1359600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1360600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // If a dialog has already been created for this response,
1361600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // pass it up.
1362600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        SIPDialog dialog = null;
1363600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String method = sipResponse.getCSeq().getMethod();
1364600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String dialogId = sipResponse.getDialogId(false);
1365600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (method.equals(Request.CANCEL) && lastRequest != null) {
1366600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // JvB for CANCEL: use invite CT in CANCEL request to get dialog
1367600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // (instead of stripping tag)
1368600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            SIPClientTransaction ict = (SIPClientTransaction) lastRequest.getInviteTransaction();
1369600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (ict != null) {
1370600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                dialog = ict.defaultDialog;
1371600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
1372600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else {
1373600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            dialog = this.getDialog(dialogId);
1374600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1375600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1376600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // JvB: Check all conditions required for creating a new Dialog
1377600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (dialog == null) {
1378600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            int code = sipResponse.getStatusCode();
1379600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if ((code > 100 && code < 300)
1380600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            /* skip 100 (may have a to tag */
1381600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            && (sipResponse.getToTag() != null || sipStack.isRfc2543Supported())
1382600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    && sipStack.isDialogCreated(method)) {
1383600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1384600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                /*
1385600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                 * Dialog cannot be found for the response. This must be a forked response. no
1386600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                 * dialog assigned to this response but a default dialog has been assigned. Note
1387600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                 * that if automatic dialog support is configured then a default dialog is always
1388600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                 * created.
1389600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                 */
1390600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1391600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                synchronized (this) {
1392600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    /*
1393600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                     * We need synchronization here because two responses may compete for the
1394600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                     * default dialog simultaneously
1395600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                     */
1396600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (defaultDialog != null) {
1397600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        if (sipResponse.getFromTag() != null) {
1398600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            SIPResponse dialogResponse = defaultDialog.getLastResponse();
1399600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            String defaultDialogId = defaultDialog.getDialogId();
1400600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            if (dialogResponse == null
1401600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                    || (method.equals(Request.SUBSCRIBE)
1402600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                            && dialogResponse.getCSeq().getMethod().equals(
1403600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                                    Request.NOTIFY) && defaultDialogId
1404600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                            .equals(dialogId))) {
1405600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                // The default dialog has not been claimed yet.
1406600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                defaultDialog.setLastResponse(this, sipResponse);
1407600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                dialog = defaultDialog;
1408600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            } else {
1409600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                /*
1410600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                 * check if we have created one previously (happens in the case of
1411600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                 * REINVITE processing. JvB: should not happen, this.defaultDialog
1412600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                 * should then get set in Dialog#sendRequest line 1662
1413600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                 */
1414600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1415600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                dialog = sipStack.getDialog(dialogId);
1416600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                if (dialog == null) {
1417600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                    if (defaultDialog.isAssigned()) {
1418600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                        /*
1419600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                         * Nop we dont have one. so go ahead and allocate a new
1420600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                         * one.
1421600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                         */
1422600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                        dialog = sipStack.createDialog(this, sipResponse);
1423600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1424600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                    }
1425600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                }
1426600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1427600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            }
1428600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            if ( dialog != null ) {
1429600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                this.setDialog(dialog, dialog.getDialogId());
1430600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            } else {
1431600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                sipStack.getStackLogger().logError("dialog is unexpectedly null",new NullPointerException());
1432600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            }
1433600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        } else {
1434600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            throw new RuntimeException("Response without from-tag");
1435600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        }
1436600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    } else {
1437600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        // Need to create a new Dialog, this becomes default
1438600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        // JvB: not sure if this ever gets executed
1439600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        if (sipStack.isAutomaticDialogSupportEnabled) {
1440600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            dialog = sipStack.createDialog(this, sipResponse);
1441600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            this.setDialog(dialog, dialog.getDialogId());
1442600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        }
1443600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
1444600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } // synchronized
1445600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } else {
1446600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                dialog = defaultDialog;
1447600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
1448600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else {
1449600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            dialog.setLastResponse(this, sipResponse);
1450600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1451600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.processResponse(sipResponse, incomingChannel, dialog);
1452600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1453600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1454600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
1455600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * (non-Javadoc)
1456600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1457600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @see gov.nist.javax.sip.stack.SIPTransaction#getDialog()
1458600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1459600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public  Dialog getDialog() {
1460600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // This is for backwards compatibility.
1461600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        Dialog retval = null;
1462600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (this.lastResponse != null && this.lastResponse.getFromTag() != null
1463600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                && this.lastResponse.getToTag() != null
1464600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                && this.lastResponse.getStatusCode() != 100) {
1465600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            String dialogId = this.lastResponse.getDialogId(false);
1466600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            retval = (Dialog) getDialog(dialogId);
1467600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1468600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1469600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (retval == null) {
1470600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            retval = (Dialog) this.defaultDialog;
1471600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1472600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1473600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (sipStack.isLoggingEnabled()) {
1474600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            sipStack.getStackLogger().logDebug(
1475600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    " sipDialogs =  " + sipDialogs + " default dialog " + this.defaultDialog
1476600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            + " retval " + retval);
1477600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1478600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return retval;
1479600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1480600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1481600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1482600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
1483600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * (non-Javadoc)
1484600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1485600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @see gov.nist.javax.sip.stack.SIPTransaction#setDialog(gov.nist.javax.sip.stack.SIPDialog,
1486600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *      gov.nist.javax.sip.message.SIPMessage)
1487600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1488600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public SIPDialog getDialog(String dialogId) {
1489600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        SIPDialog retval = (SIPDialog) this.sipDialogs.get(dialogId);
1490600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return retval;
1491600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1492600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1493600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1494600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
1495600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * (non-Javadoc)
1496600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1497600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @see gov.nist.javax.sip.stack.SIPTransaction#setDialog(gov.nist.javax.sip.stack.SIPDialog,
1498600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *      gov.nist.javax.sip.message.SIPMessage)
1499600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1500600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void setDialog(SIPDialog sipDialog, String dialogId) {
1501600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (sipStack.isLoggingEnabled())
1502600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            sipStack.getStackLogger().logDebug(
1503600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    "setDialog: " + dialogId + "sipDialog = " + sipDialog);
1504600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1505600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (sipDialog == null) {
1506600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        	if (sipStack.isLoggingEnabled())
1507600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        		sipStack.getStackLogger().logError("NULL DIALOG!!");
1508600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw new NullPointerException("bad dialog null");
1509600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1510600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (this.defaultDialog == null) {
1511600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.defaultDialog = sipDialog;
1512600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if ( this.getMethod().equals(Request.INVITE) && this.getSIPStack().maxForkTime != 0) {
1513600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                this.getSIPStack().addForkedClientTransaction(this);
1514600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
1515600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1516600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (dialogId != null && sipDialog.getDialogId() != null) {
1517600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.sipDialogs.put(dialogId, sipDialog);
1518600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1519600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1520600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1521600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1522600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1523600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public SIPDialog getDefaultDialog() {
1524600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return this.defaultDialog;
1525600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1526600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1527600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1528600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Set the next hop ( if it has already been computed).
1529600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1530600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param hop -- the hop that has been previously computed.
1531600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1532600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void setNextHop(Hop hop) {
1533600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.nextHop = hop;
1534600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1535600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1536600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1537600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1538600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Reeturn the previously computed next hop (avoid computing it twice).
1539600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1540600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return -- next hop previously computed.
1541600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1542600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public Hop getNextHop() {
1543600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return nextHop;
1544600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1545600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1546600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1547600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Set this flag if you want your Listener to get Timeout.RETRANSMIT notifications each time a
1548600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * retransmission occurs.
1549600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1550600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param notifyOnRetransmit the notifyOnRetransmit to set
1551600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1552600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void setNotifyOnRetransmit(boolean notifyOnRetransmit) {
1553600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.notifyOnRetransmit = notifyOnRetransmit;
1554600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1555600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1556600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1557600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return the notifyOnRetransmit
1558600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1559600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public boolean isNotifyOnRetransmit() {
1560600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return notifyOnRetransmit;
1561600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1562600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1563600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void alertIfStillInCallingStateBy(int count) {
1564600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.timeoutIfStillInCallingState = true;
1565600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.callingStateTimeoutCount = count;
1566600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1567600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1568600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1569600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1570600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang}
1571