• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2   * Conditions Of Use
3   *
4   * This software was developed by employees of the National Institute of
5   * Standards and Technology (NIST), an agency of the Federal Government.
6   * Pursuant to title 15 Untied States Code Section 105, works of NIST
7   * employees are not subject to copyright protection in the United States
8   * and are considered to be in the public domain.  As a result, a formal
9   * license is not needed to use the software.
10   *
11   * This software is provided by NIST as a service and is expressly
12   * provided "AS IS."  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
13   * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
14   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
15   * AND DATA ACCURACY.  NIST does not warrant or make any representations
16   * regarding the use of the software or the results thereof, including but
17   * not limited to the correctness, accuracy, reliability or usefulness of
18   * the software.
19   *
20   * Permission to use this software is contingent upon your acceptance
21   * of the terms of this agreement
22   *
23   * .
24   *
25   */
26  /**************************************************************************/
27  /* Product of NIST Advanced Networking Technologies Division      */
28  /**************************************************************************/
29  package gov.nist.javax.sip.stack;
30  
31  import gov.nist.core.InternalErrorHandler;
32  import gov.nist.core.NameValueList;
33  import gov.nist.javax.sip.DialogExt;
34  import gov.nist.javax.sip.ListeningPointImpl;
35  import gov.nist.javax.sip.SipListenerExt;
36  import gov.nist.javax.sip.SipProviderImpl;
37  import gov.nist.javax.sip.Utils;
38  import gov.nist.javax.sip.address.AddressImpl;
39  import gov.nist.javax.sip.address.SipUri;
40  import gov.nist.javax.sip.header.Authorization;
41  import gov.nist.javax.sip.header.CSeq;
42  import gov.nist.javax.sip.header.Contact;
43  import gov.nist.javax.sip.header.ContactList;
44  import gov.nist.javax.sip.header.From;
45  import gov.nist.javax.sip.header.MaxForwards;
46  import gov.nist.javax.sip.header.RAck;
47  import gov.nist.javax.sip.header.RSeq;
48  import gov.nist.javax.sip.header.Reason;
49  import gov.nist.javax.sip.header.RecordRoute;
50  import gov.nist.javax.sip.header.RecordRouteList;
51  import gov.nist.javax.sip.header.Require;
52  import gov.nist.javax.sip.header.Route;
53  import gov.nist.javax.sip.header.RouteList;
54  import gov.nist.javax.sip.header.SIPHeader;
55  import gov.nist.javax.sip.header.TimeStamp;
56  import gov.nist.javax.sip.header.To;
57  import gov.nist.javax.sip.header.Via;
58  import gov.nist.javax.sip.message.MessageFactoryImpl;
59  import gov.nist.javax.sip.message.SIPMessage;
60  import gov.nist.javax.sip.message.SIPRequest;
61  import gov.nist.javax.sip.message.SIPResponse;
62  
63  import java.io.IOException;
64  import java.io.PrintWriter;
65  import java.io.Serializable;
66  import java.io.StringWriter;
67  import java.net.InetAddress;
68  import java.text.ParseException;
69  import java.util.ArrayList;
70  import java.util.Iterator;
71  import java.util.LinkedList;
72  import java.util.List;
73  import java.util.ListIterator;
74  import java.util.Set;
75  import java.util.concurrent.CopyOnWriteArraySet;
76  import java.util.concurrent.Semaphore;
77  import java.util.concurrent.TimeUnit;
78  
79  import javax.sip.ClientTransaction;
80  import javax.sip.DialogDoesNotExistException;
81  import javax.sip.DialogState;
82  import javax.sip.IOExceptionEvent;
83  import javax.sip.InvalidArgumentException;
84  import javax.sip.ListeningPoint;
85  import javax.sip.ObjectInUseException;
86  import javax.sip.SipException;
87  import javax.sip.Transaction;
88  import javax.sip.TransactionDoesNotExistException;
89  import javax.sip.TransactionState;
90  import javax.sip.address.Address;
91  import javax.sip.address.Hop;
92  import javax.sip.address.SipURI;
93  import javax.sip.header.CallIdHeader;
94  import javax.sip.header.ContactHeader;
95  import javax.sip.header.EventHeader;
96  import javax.sip.header.OptionTag;
97  import javax.sip.header.RAckHeader;
98  import javax.sip.header.RSeqHeader;
99  import javax.sip.header.ReasonHeader;
100  import javax.sip.header.RequireHeader;
101  import javax.sip.header.RouteHeader;
102  import javax.sip.header.SupportedHeader;
103  import javax.sip.header.TimeStampHeader;
104  import javax.sip.message.Request;
105  import javax.sip.message.Response;
106  
107  /*
108   * Acknowledgements:
109   *
110   * Bugs in this class were reported by Antonis Karydas, Brad Templeton, Jeff Adams, Alex Rootham ,
111   * Martin Le Clerk, Christophe Anzille, Andreas Bystrom, Lebing Xie, Jeroen van Bemmel. Hagai Sela
112   * reported a bug in updating the route set (on RE-INVITE). Jens Tinfors submitted a bug fix and
113   * the .equals method. Jan Schaumloeffel contributed a buf fix ( memory leak was happening when
114   * 180 contained a To tag.
115   *
116   */
117  
118  /**
119   * Tracks dialogs. A dialog is a peer to peer association of communicating SIP entities. For
120   * INVITE transactions, a Dialog is created when a success message is received (i.e. a response
121   * that has a To tag). The SIP Protocol stores enough state in the message structure to extract a
122   * dialog identifier that can be used to retrieve this structure from the SipStack.
123   *
124   * @version 1.2 $Revision: 1.159 $ $Date: 2010/01/08 15:14:12 $
125   *
126   * @author M. Ranganathan
127   *
128   *
129   */
130  
131  public class SIPDialog implements javax.sip.Dialog, DialogExt {
132  
133      private static final long serialVersionUID = -1429794423085204069L;
134  
135      private transient boolean dialogTerminatedEventDelivered; // prevent duplicate
136  
137      private transient String stackTrace; // for semaphore debugging.
138  
139      private String method;
140  
141      // delivery of the event
142      private transient boolean isAssigned;
143  
144      private boolean reInviteFlag;
145  
146      private transient Object applicationData; // Opaque pointer to application data.
147  
148      private transient SIPRequest originalRequest;
149  
150      // Last response (JvB: either sent or received).
151      private SIPResponse lastResponse;
152  
153      // Should be transient, in case the dialog is serialized it will be null
154      // so when a subsequent request will be sent it will be set and a new message channel can be
155      // created
156      private transient SIPTransaction firstTransaction;
157  
158      private transient SIPTransaction lastTransaction;
159  
160      private String dialogId;
161  
162      private transient String earlyDialogId;
163  
164      private long localSequenceNumber;
165  
166      private long remoteSequenceNumber;
167  
168      protected String myTag;
169  
170      protected String hisTag;
171  
172      private RouteList routeList;
173  
174      private transient SIPTransactionStack sipStack;
175  
176      private int dialogState;
177  
178      protected transient boolean ackSeen;
179  
180      private transient SIPRequest lastAckSent;
181  
182      private SIPRequest lastAckReceived;
183  
184      // could be set on recovery by examining the method looks like a duplicate of ackSeen
185      protected transient boolean ackProcessed;
186  
187      protected transient DialogTimerTask timerTask;
188  
189      protected transient Long nextSeqno;
190  
191      private transient int retransmissionTicksLeft;
192  
193      private transient int prevRetransmissionTicks;
194  
195      private long originalLocalSequenceNumber;
196  
197      // This is for debugging only.
198      private transient int ackLine;
199  
200      // Audit tag used by the SIP Stack audit
201      public transient long auditTag = 0;
202  
203      // The following fields are extracted from the request that created the
204      // Dialog.
205  
206      protected javax.sip.address.Address localParty;
207  
208      protected javax.sip.address.Address remoteParty;
209  
210      protected CallIdHeader callIdHeader;
211  
212      public final static int NULL_STATE = -1;
213  
214      public final static int EARLY_STATE = DialogState._EARLY;
215  
216      public final static int CONFIRMED_STATE = DialogState._CONFIRMED;
217  
218      public final static int TERMINATED_STATE = DialogState._TERMINATED;
219  
220      // the amount of time to keep this dialog around before the stack GC's it
221  
222      private static final int DIALOG_LINGER_TIME = 8;
223  
224      private boolean serverTransactionFlag;
225  
226      private transient SipProviderImpl sipProvider;
227  
228      private boolean terminateOnBye;
229  
230      private transient boolean byeSent; // Flag set when BYE is sent, to disallow new
231  
232      // requests
233  
234      private Address remoteTarget;
235  
236      private EventHeader eventHeader; // for Subscribe notify
237  
238      // Stores the last OK for the INVITE
239      // Used in createAck.
240      private transient long lastInviteOkReceived;
241  
242      private transient Semaphore ackSem = new Semaphore(1);
243  
244      private transient int reInviteWaitTime = 100;
245  
246      private transient DialogDeleteTask dialogDeleteTask;
247  
248  	private transient DialogDeleteIfNoAckSentTask dialogDeleteIfNoAckSentTask;
249  
250      private transient boolean isAcknowledged;
251  
252      private transient long highestSequenceNumberAcknowledged = -1;
253  
254      private boolean isBackToBackUserAgent;
255  
256      private boolean sequenceNumberValidation = true;
257  
258      // List of event listeners for this dialog
259  	private transient Set<SIPDialogEventListener> eventListeners;
260  	// added for Issue 248 : https://jain-sip.dev.java.net/issues/show_bug.cgi?id=248
261  	private Semaphore timerTaskLock = new Semaphore(1);
262  
263  	// We store here the useful data from the first transaction without having to
264  	// keep the whole transaction object for the duration of the dialog. It also
265  	// contains the non-transient information used in the replication of dialogs.
266  	protected boolean firstTransactionSecure;
267  	protected boolean firstTransactionSeen;
268      protected String firstTransactionMethod;
269      protected String firstTransactionId;
270      protected boolean firstTransactionIsServerTransaction;
271      protected int firstTransactionPort = 5060;
272      protected Contact contactHeader;
273  
274      // //////////////////////////////////////////////////////
275      // Inner classes
276      // //////////////////////////////////////////////////////
277  
278      /**
279       * This task waits till a pending ACK has been recorded and then sends out a re-INVITE. This
280       * is to prevent interleaving INVITEs ( which will result in a 493 from the UA that receives
281       * the out of order INVITE). This is primarily for B2BUA support. A B2BUA may send a delayed
282       * ACK while it does mid call codec renegotiation. In the meanwhile, it cannot send an intervening
283       * re-INVITE otherwise the othr end will respond with a REQUEST_PENDING. We want to avoid this
284       * condition. Hence we wait till the ACK for the previous re-INVITE has been sent before
285       * sending the next re-INVITE.
286       */
287      public class ReInviteSender implements Runnable, Serializable {
288          private static final long serialVersionUID = 1019346148741070635L;
289          ClientTransaction ctx;
290  
terminate()291          public void terminate() {
292              try {
293                  ctx.terminate();
294                  Thread.currentThread().interrupt();
295              } catch (ObjectInUseException e) {
296                  sipStack.getStackLogger().logError("unexpected error", e);
297              }
298          }
299  
ReInviteSender(ClientTransaction ctx)300          public ReInviteSender(ClientTransaction ctx) {
301              this.ctx = ctx;
302          }
303  
run()304          public void run() {
305              try {
306                  long timeToWait = 0;
307                  long startTime = System.currentTimeMillis();
308  
309                  if (!SIPDialog.this.takeAckSem()) {
310                      /*
311                       * Could not send re-INVITE fire a timeout on the INVITE.
312                       */
313                  	if (sipStack.isLoggingEnabled())
314                  		sipStack.getStackLogger().logError(
315                              "Could not send re-INVITE time out ClientTransaction");
316                      ((SIPClientTransaction) ctx).fireTimeoutTimer();
317                      /*
318                       * Send BYE to the Dialog.
319                       */
320                      if ( sipProvider.getSipListener() != null && sipProvider.getSipListener() instanceof SipListenerExt ) {
321                          raiseErrorEvent(SIPDialogErrorEvent.DIALOG_REINVITE_TIMEOUT);
322                      } else {
323                          Request byeRequest = SIPDialog.this.createRequest(Request.BYE);
324                          if ( MessageFactoryImpl.getDefaultUserAgentHeader() != null ) {
325                              byeRequest.addHeader(MessageFactoryImpl.getDefaultUserAgentHeader());
326                          }
327                          ReasonHeader reasonHeader = new Reason();
328                          reasonHeader.setCause(1024);
329                          reasonHeader.setText("Timed out waiting to re-INVITE");
330                          byeRequest.addHeader(reasonHeader);
331                          ClientTransaction byeCtx = SIPDialog.this.getSipProvider().getNewClientTransaction(byeRequest);
332                          SIPDialog.this.sendRequest(byeCtx);
333                          return;
334                      }
335                  }
336                  if (getState() != DialogState.TERMINATED) {
337  
338                      timeToWait = System.currentTimeMillis() - startTime;
339                  }
340  
341                  /*
342                   * If we had to wait for ACK then wait for the ACK to actually get to the other
343                   * side. Wait for any ACK retransmissions to finish. Then send out the request.
344                   * This is a hack in support of some UA that want re-INVITEs to be spaced out in
345                   * time ( else they return a 400 error code ).
346                   */
347                  try {
348                      if (timeToWait != 0) {
349                          Thread.sleep(SIPDialog.this.reInviteWaitTime);
350                      }
351                  } catch (InterruptedException ex) {
352                  	if (sipStack.isLoggingEnabled())
353                  		sipStack.getStackLogger().logDebug("Interrupted sleep");
354                      return;
355                  }
356                  if (SIPDialog.this.getState() != DialogState.TERMINATED) {
357                      SIPDialog.this.sendRequest(ctx, true);
358                  }
359                  if (sipStack.isLoggingEnabled())
360                  	sipStack.getStackLogger().logDebug("re-INVITE successfully sent");
361              } catch (Exception ex) {
362                  sipStack.getStackLogger().logError("Error sending re-INVITE", ex);
363              } finally {
364                  this.ctx = null;
365              }
366          }
367      }
368  
369  	class LingerTimer extends SIPStackTimerTask implements Serializable {
370  
LingerTimer()371          public LingerTimer() {
372  
373          }
374  
runTask()375          protected void runTask() {
376              SIPDialog dialog = SIPDialog.this;
377              if(eventListeners != null) {
378              	eventListeners.clear();
379              }
380              timerTaskLock = null;
381              sipStack.removeDialog(dialog);
382          }
383  
384      }
385  
386      class DialogTimerTask extends SIPStackTimerTask implements Serializable {
387          int nRetransmissions;
388  
389          SIPServerTransaction transaction;
390  
DialogTimerTask(SIPServerTransaction transaction)391          public DialogTimerTask(SIPServerTransaction transaction) {
392              this.transaction = transaction;
393              this.nRetransmissions = 0;
394          }
395  
runTask()396          protected void runTask() {
397              // If I ACK has not been seen on Dialog,
398              // resend last response.
399              SIPDialog dialog = SIPDialog.this;
400              if (sipStack.isLoggingEnabled())
401                  sipStack.getStackLogger().logDebug("Running dialog timer");
402              nRetransmissions++;
403              SIPServerTransaction transaction = this.transaction;
404              /*
405               * Issue 106. Section 13.3.1.4 RFC 3261 The 2xx response is passed to the transport
406               * with an interval that starts at T1 seconds and doubles for each retransmission
407               * until it reaches T2 seconds If the server retransmits the 2xx response for 64*T1
408               * seconds without receiving an ACK, the dialog is confirmed, but the session SHOULD
409               * be terminated.
410               */
411  
412              if (nRetransmissions > 64 * SIPTransaction.T1) {
413                  if (sipProvider.getSipListener() != null && sipProvider.getSipListener() instanceof SipListenerExt ) {
414                      raiseErrorEvent(SIPDialogErrorEvent.DIALOG_ACK_NOT_RECEIVED_TIMEOUT);
415                  } else  {
416                      dialog.delete();
417                  }
418                  if (transaction != null
419                          && transaction.getState() != javax.sip.TransactionState.TERMINATED) {
420                      transaction.raiseErrorEvent(SIPTransactionErrorEvent.TIMEOUT_ERROR);
421                  }
422              } else if ((!dialog.ackSeen) && (transaction != null)) {
423                  // Retransmit to 200 until ack receivedialog.
424                  SIPResponse response = transaction.getLastResponse();
425                  if (response.getStatusCode() == 200) {
426                      try {
427  
428                          // resend the last response.
429                          if (dialog.toRetransmitFinalResponse(transaction.T2))
430                              transaction.sendMessage(response);
431  
432                      } catch (IOException ex) {
433  
434                          raiseIOException(transaction.getPeerAddress(), transaction.getPeerPort(),
435                                  transaction.getPeerProtocol());
436  
437                      } finally {
438                          // Need to fire the timer so
439                          // transaction will eventually
440                          // time out whether or not
441                          // the IOException occurs
442                          // Note that this firing also
443                          // drives Listener timeout.
444                          SIPTransactionStack stack = dialog.sipStack;
445                          if (stack.isLoggingEnabled()) {
446                              stack.getStackLogger().logDebug("resend 200 response from " + dialog);
447                          }
448                          transaction.fireTimer();
449                      }
450                  }
451              }
452  
453              // Stop running this timer if the dialog is in the
454              // confirmed state or ack seen if retransmit filter on.
455              if (dialog.isAckSeen() || dialog.dialogState == TERMINATED_STATE) {
456                  this.transaction = null;
457                  this.cancel();
458  
459              }
460  
461          }
462  
463      }
464  
465      /**
466       * This timer task is used to garbage collect the dialog after some time.
467       *
468       */
469  
470      class DialogDeleteTask extends SIPStackTimerTask implements Serializable {
471  
runTask()472          protected void runTask() {
473              delete();
474          }
475  
476      }
477  
478      /**
479       * This timer task is used to garbage collect the dialog after some time.
480       *
481       */
482  
483      class DialogDeleteIfNoAckSentTask extends SIPStackTimerTask implements Serializable {
484          private long seqno;
485  
DialogDeleteIfNoAckSentTask(long seqno)486          public DialogDeleteIfNoAckSentTask(long seqno) {
487              this.seqno = seqno;
488          }
489  
runTask()490          protected void runTask() {
491              if (SIPDialog.this.highestSequenceNumberAcknowledged < seqno) {
492                  /*
493                   * Did not send ACK so we need to delete the dialog.
494                   * B2BUA NOTE: we may want to send BYE to the Dialog at this
495                   * point. Do we want to make this behavior tailorable?
496                   */
497              	dialogDeleteIfNoAckSentTask = null;
498                  if ( !SIPDialog.this.isBackToBackUserAgent) {
499                  	if (sipStack.isLoggingEnabled())
500                  		sipStack.getStackLogger().logError("ACK Was not sent. killing dialog");
501                  	if ( ((SipProviderImpl)sipProvider).getSipListener() instanceof SipListenerExt ){
502                  	    raiseErrorEvent(SIPDialogErrorEvent.DIALOG_ACK_NOT_SENT_TIMEOUT);
503                  	} else {
504                  	    delete();
505                  	}
506                  } else {
507                  	if (sipStack.isLoggingEnabled())
508                  		sipStack.getStackLogger().logError("ACK Was not sent. Sending BYE");
509                  	   if ( ((SipProviderImpl)sipProvider).getSipListener() instanceof SipListenerExt ){
510                  	       raiseErrorEvent(SIPDialogErrorEvent.DIALOG_ACK_NOT_SENT_TIMEOUT);
511                  	   } else {
512  
513                          /*
514                           * Send BYE to the Dialog.
515                           * This will be removed for the next spec revision.
516                           */
517                          try {
518                              Request byeRequest = SIPDialog.this.createRequest(Request.BYE);
519                              if ( MessageFactoryImpl.getDefaultUserAgentHeader() != null ) {
520                                  byeRequest.addHeader(MessageFactoryImpl.getDefaultUserAgentHeader());
521                              }
522                              ReasonHeader reasonHeader = new Reason();
523                              reasonHeader.setProtocol("SIP");
524                              reasonHeader.setCause(1025);
525                              reasonHeader.setText("Timed out waiting to send ACK");
526                              byeRequest.addHeader(reasonHeader);
527                              ClientTransaction byeCtx = SIPDialog.this.getSipProvider().getNewClientTransaction(byeRequest);
528                              SIPDialog.this.sendRequest(byeCtx);
529                              return;
530                          } catch (Exception ex) {
531                              SIPDialog.this.delete();
532                          }
533                      }
534                  }
535              }
536          }
537  
538      }
539  
540      // ///////////////////////////////////////////////////////////
541      // Constructors.
542      // ///////////////////////////////////////////////////////////
543      /**
544       * Protected Dialog constructor.
545       */
SIPDialog(SipProviderImpl provider)546      private SIPDialog(SipProviderImpl provider) {
547          this.terminateOnBye = true;
548          this.routeList = new RouteList();
549          this.dialogState = NULL_STATE; // not yet initialized.
550          localSequenceNumber = 0;
551          remoteSequenceNumber = -1;
552          this.sipProvider = provider;
553          eventListeners = new CopyOnWriteArraySet<SIPDialogEventListener>();
554      }
555  
recordStackTrace()556      private void recordStackTrace() {
557        StringWriter stringWriter = new StringWriter();
558        PrintWriter writer = new PrintWriter(stringWriter);
559        new Exception().printStackTrace(writer);
560         this.stackTrace = stringWriter.getBuffer().toString();
561      }
562  
563      /**
564       * Constructor given the first transaction.
565       *
566       * @param transaction is the first transaction.
567       */
SIPDialog(SIPTransaction transaction)568      public SIPDialog(SIPTransaction transaction) {
569          this(transaction.getSipProvider());
570  
571          SIPRequest sipRequest = (SIPRequest) transaction.getRequest();
572          this.callIdHeader = sipRequest.getCallId();
573          this.earlyDialogId = sipRequest.getDialogId(false);
574          if (transaction == null)
575              throw new NullPointerException("Null tx");
576          this.sipStack = transaction.sipStack;
577  
578          // this.defaultRouter = new DefaultRouter((SipStack) sipStack,
579          // sipStack.outboundProxy);
580  
581          this.sipProvider = (SipProviderImpl) transaction.getSipProvider();
582          if (sipProvider == null)
583              throw new NullPointerException("Null Provider!");
584          this.addTransaction(transaction);
585          if (sipStack.isLoggingEnabled()) {
586              sipStack.getStackLogger().logDebug("Creating a dialog : " + this);
587              sipStack.getStackLogger().logDebug(
588                      "provider port = " + this.sipProvider.getListeningPoint().getPort());
589              sipStack.getStackLogger().logStackTrace();
590          }
591          this.isBackToBackUserAgent = sipStack.isBackToBackUserAgent;
592          addEventListener(sipStack);
593      }
594  
595      /**
596       * Constructor given a transaction and a response.
597       *
598       * @param transaction -- the transaction ( client/server)
599       * @param sipResponse -- response with the appropriate tags.
600       */
SIPDialog(SIPClientTransaction transaction, SIPResponse sipResponse)601      public SIPDialog(SIPClientTransaction transaction, SIPResponse sipResponse) {
602          this(transaction);
603          if (sipResponse == null)
604              throw new NullPointerException("Null SipResponse");
605          this.setLastResponse(transaction, sipResponse);
606          this.isBackToBackUserAgent = sipStack.isBackToBackUserAgent;
607      }
608  
609      /**
610       * create a sip dialog with a response ( no tx)
611       */
SIPDialog(SipProviderImpl sipProvider, SIPResponse sipResponse)612      public SIPDialog(SipProviderImpl sipProvider, SIPResponse sipResponse) {
613          this(sipProvider);
614          this.sipStack = (SIPTransactionStack) sipProvider.getSipStack();
615          this.setLastResponse(null, sipResponse);
616          this.localSequenceNumber = sipResponse.getCSeq().getSeqNumber();
617          this.originalLocalSequenceNumber = localSequenceNumber;
618          this.myTag = sipResponse.getFrom().getTag();
619          this.hisTag = sipResponse.getTo().getTag();
620          this.localParty = sipResponse.getFrom().getAddress();
621          this.remoteParty = sipResponse.getTo().getAddress();
622          this.method = sipResponse.getCSeq().getMethod();
623          this.callIdHeader = sipResponse.getCallId();
624          this.serverTransactionFlag = false;
625          if (sipStack.isLoggingEnabled()) {
626              sipStack.getStackLogger().logDebug("Creating a dialog : " + this);
627              sipStack.getStackLogger().logStackTrace();
628          }
629          this.isBackToBackUserAgent = sipStack.isBackToBackUserAgent;
630          addEventListener(sipStack);
631      }
632  
633      // ///////////////////////////////////////////////////////////
634      // Private methods
635      // ///////////////////////////////////////////////////////////
636      /**
637       * A debugging print routine.
638       */
printRouteList()639      private void printRouteList() {
640          if (sipStack.isLoggingEnabled()) {
641              sipStack.getStackLogger().logDebug("this : " + this);
642              sipStack.getStackLogger().logDebug("printRouteList : " + this.routeList.encode());
643          }
644      }
645  
646      /**
647       * Return true if this is a client dialog.
648       *
649       * @return true if the transaction that created this dialog is a client transaction and false
650       *         otherwise.
651       */
isClientDialog()652      private boolean isClientDialog() {
653          SIPTransaction transaction = (SIPTransaction) this.getFirstTransaction();
654          return transaction instanceof SIPClientTransaction;
655      }
656  
657      /**
658       * Raise an io exception for asyncrhonous retransmission of responses
659       *
660       * @param host -- host to where the io was headed
661       * @param port -- remote port
662       * @param protocol -- protocol (udp/tcp/tls)
663       */
raiseIOException(String host, int port, String protocol)664      private void raiseIOException(String host, int port, String protocol) {
665          // Error occured in retransmitting response.
666          // Deliver the error event to the listener
667          // Kill the dialog.
668  
669          IOExceptionEvent ioError = new IOExceptionEvent(this, host, port, protocol);
670          sipProvider.handleEvent(ioError, null);
671  
672          setState(SIPDialog.TERMINATED_STATE);
673      }
674  
675      /**
676       * Raise a dialog timeout if an ACK has not been sent or received
677       *
678       * @param dialogTimeoutError
679       */
raiseErrorEvent(int dialogTimeoutError)680      private void raiseErrorEvent(int dialogTimeoutError) {
681  		// Error event to send to all listeners
682  		SIPDialogErrorEvent newErrorEvent;
683  		// Iterator through the list of listeners
684  		Iterator<SIPDialogEventListener> listenerIterator;
685  		// Next listener in the list
686  		SIPDialogEventListener nextListener;
687  
688  		// Create the error event
689  		newErrorEvent = new SIPDialogErrorEvent(this, dialogTimeoutError);
690  
691  		// Loop through all listeners of this transaction
692  		synchronized (eventListeners) {
693  			listenerIterator = eventListeners.iterator();
694  			while (listenerIterator.hasNext()) {
695  				// Send the event to the next listener
696  				nextListener = (SIPDialogEventListener) listenerIterator.next();
697  				nextListener.dialogErrorEvent(newErrorEvent);
698  			}
699  		}
700  		// Clear the event listeners after propagating the error.
701  		eventListeners.clear();
702  		// Errors always terminate a dialog except if a timeout has occured because an ACK was not sent or received, then it is the responsibility of the app to terminate
703  		// the dialog, either by sending a BYE or by calling delete() on the dialog
704  		if(dialogTimeoutError != SIPDialogErrorEvent.DIALOG_ACK_NOT_SENT_TIMEOUT &&
705  		        dialogTimeoutError != SIPDialogErrorEvent.DIALOG_ACK_NOT_RECEIVED_TIMEOUT &&
706  		        dialogTimeoutError != SIPDialogErrorEvent.DIALOG_REINVITE_TIMEOUT ) {
707  			delete();
708  		}
709  		// we stop the timer in any case
710  		stopTimer();
711  	}
712  
713      /**
714       * Set the remote party for this Dialog.
715       *
716       * @param sipMessage -- SIP Message to extract the relevant information from.
717       */
setRemoteParty(SIPMessage sipMessage)718      private void setRemoteParty(SIPMessage sipMessage) {
719  
720          if (!isServer()) {
721  
722              this.remoteParty = sipMessage.getTo().getAddress();
723          } else {
724              this.remoteParty = sipMessage.getFrom().getAddress();
725  
726          }
727          if (sipStack.isLoggingEnabled()) {
728              sipStack.getStackLogger().logDebug("settingRemoteParty " + this.remoteParty);
729          }
730      }
731  
732      /**
733       * Add a route list extracted from a record route list. If this is a server dialog then we
734       * assume that the record are added to the route list IN order. If this is a client dialog
735       * then we assume that the record route headers give us the route list to add in reverse
736       * order.
737       *
738       * @param recordRouteList -- the record route list from the incoming message.
739       */
740  
addRoute(RecordRouteList recordRouteList)741      private void addRoute(RecordRouteList recordRouteList) {
742          try {
743              if (this.isClientDialog()) {
744                  // This is a client dialog so we extract the record
745                  // route from the response and reverse its order to
746                  // careate a route list.
747                  this.routeList = new RouteList();
748                  // start at the end of the list and walk backwards
749  
750                  ListIterator li = recordRouteList.listIterator(recordRouteList.size());
751                  boolean addRoute = true;
752                  while (li.hasPrevious()) {
753                      RecordRoute rr = (RecordRoute) li.previous();
754  
755                      if (addRoute) {
756                          Route route = new Route();
757                          AddressImpl address = ((AddressImpl) ((AddressImpl) rr.getAddress())
758                                  .clone());
759  
760                          route.setAddress(address);
761                          route.setParameters((NameValueList) rr.getParameters().clone());
762  
763                          this.routeList.add(route);
764                      }
765                  }
766              } else {
767                  // This is a server dialog. The top most record route
768                  // header is the one that is closest to us. We extract the
769                  // route list in the same order as the addresses in the
770                  // incoming request.
771                  this.routeList = new RouteList();
772                  ListIterator li = recordRouteList.listIterator();
773                  boolean addRoute = true;
774                  while (li.hasNext()) {
775                      RecordRoute rr = (RecordRoute) li.next();
776  
777                      if (addRoute) {
778                          Route route = new Route();
779                          AddressImpl address = ((AddressImpl) ((AddressImpl) rr.getAddress())
780                                  .clone());
781                          route.setAddress(address);
782                          route.setParameters((NameValueList) rr.getParameters().clone());
783                          routeList.add(route);
784                      }
785                  }
786              }
787          } finally {
788              if (sipStack.getStackLogger().isLoggingEnabled()) {
789                  Iterator it = routeList.iterator();
790  
791                  while (it.hasNext()) {
792                      SipURI sipUri = (SipURI) (((Route) it.next()).getAddress().getURI());
793                      if (!sipUri.hasLrParam()) {
794                      	if (sipStack.isLoggingEnabled()) {
795                      		sipStack.getStackLogger().logWarning(
796                                  "NON LR route in Route set detected for dialog : " + this);
797                          	sipStack.getStackLogger().logStackTrace();
798                      	}
799                      }
800                  }
801              }
802          }
803      }
804  
805      /**
806       * Add a route list extacted from the contact list of the incoming message.
807       *
808       * @param contactList -- contact list extracted from the incoming message.
809       *
810       */
811  
setRemoteTarget(ContactHeader contact)812      void setRemoteTarget(ContactHeader contact) {
813          this.remoteTarget = contact.getAddress();
814          if (sipStack.isLoggingEnabled()) {
815              sipStack.getStackLogger().logDebug("Dialog.setRemoteTarget: " + this.remoteTarget);
816              sipStack.getStackLogger().logStackTrace();
817          }
818  
819      }
820  
821      /**
822       * Extract the route information from this SIP Message and add the relevant information to the
823       * route set.
824       *
825       * @param sipMessage is the SIP message for which we want to add the route.
826       */
addRoute(SIPResponse sipResponse)827      private synchronized void addRoute(SIPResponse sipResponse) {
828  
829          try {
830              if (sipStack.isLoggingEnabled()) {
831                  sipStack.getStackLogger().logDebug(
832                          "setContact: dialogState: " + this + "state = " + this.getState());
833              }
834              if (sipResponse.getStatusCode() == 100) {
835                  // Do nothing for trying messages.
836                  return;
837              } else if (this.dialogState == TERMINATED_STATE) {
838                  // Do nothing if the dialog state is terminated.
839                  return;
840              } else if (this.dialogState == CONFIRMED_STATE) {
841                  // cannot add route list after the dialog is initialized.
842                  // Remote target is updated on RE-INVITE but not
843                  // the route list.
844                  if (sipResponse.getStatusCode() / 100 == 2 && !this.isServer()) {
845                      ContactList contactList = sipResponse.getContactHeaders();
846                      if (contactList != null
847                              && SIPRequest.isTargetRefresh(sipResponse.getCSeq().getMethod())) {
848                          this.setRemoteTarget((ContactHeader) contactList.getFirst());
849                      }
850                  }
851                  return;
852              }
853  
854              // Update route list on response if I am a client dialog.
855              if (!isServer()) {
856  
857                  // only update the route set if the dialog is not in the confirmed state.
858                  if (this.getState() != DialogState.CONFIRMED
859                          && this.getState() != DialogState.TERMINATED) {
860                      RecordRouteList rrlist = sipResponse.getRecordRouteHeaders();
861                      // Add the route set from the incoming response in reverse
862                      // order for record route headers.
863                      if (rrlist != null) {
864                          this.addRoute(rrlist);
865                      } else {
866                          // Set the rotue list to the last seen route list.
867                          this.routeList = new RouteList();
868                      }
869                  }
870  
871                  ContactList contactList = sipResponse.getContactHeaders();
872                  if (contactList != null) {
873                      this.setRemoteTarget((ContactHeader) contactList.getFirst());
874                  }
875              }
876  
877          } finally {
878              if (sipStack.isLoggingEnabled()) {
879                  sipStack.getStackLogger().logStackTrace();
880              }
881          }
882      }
883  
884      /**
885       * Get a cloned copy of route list for the Dialog.
886       *
887       * @return -- a cloned copy of the dialog route list.
888       */
getRouteList()889      private synchronized RouteList getRouteList() {
890          if (sipStack.isLoggingEnabled())
891              sipStack.getStackLogger().logDebug("getRouteList " + this);
892          // Find the top via in the route list.
893          ListIterator li;
894          RouteList retval = new RouteList();
895  
896          retval = new RouteList();
897          if (this.routeList != null) {
898              li = routeList.listIterator();
899              while (li.hasNext()) {
900                  Route route = (Route) li.next();
901                  retval.add((Route) route.clone());
902              }
903          }
904  
905          if (sipStack.isLoggingEnabled()) {
906              sipStack.getStackLogger().logDebug("----- ");
907              sipStack.getStackLogger().logDebug("getRouteList for " + this);
908              if (retval != null)
909                  sipStack.getStackLogger().logDebug("RouteList = " + retval.encode());
910              if (routeList != null)
911                  sipStack.getStackLogger().logDebug("myRouteList = " + routeList.encode());
912              sipStack.getStackLogger().logDebug("----- ");
913          }
914          return retval;
915      }
916  
setRouteList(RouteList routeList)917      void setRouteList(RouteList routeList) {
918      	this.routeList = routeList;
919      }
920  
921      /**
922       * Sends ACK Request to the remote party of this Dialogue.
923       *
924       *
925       * @param request the new ACK Request message to send.
926       * @param throwIOExceptionAsSipException - throws SipException if IOEx encountered. Otherwise,
927       *        no exception is propagated.
928       * @param releaseAckSem - release ack semaphore.
929       * @throws SipException if implementation cannot send the ACK Request for any other reason
930       *
931       */
sendAck(Request request, boolean throwIOExceptionAsSipException)932      private void sendAck(Request request, boolean throwIOExceptionAsSipException)
933              throws SipException {
934          SIPRequest ackRequest = (SIPRequest) request;
935          if (sipStack.isLoggingEnabled())
936              sipStack.getStackLogger().logDebug("sendAck" + this);
937  
938          if (!ackRequest.getMethod().equals(Request.ACK))
939              throw new SipException("Bad request method -- should be ACK");
940          if (this.getState() == null || this.getState().getValue() == EARLY_STATE) {
941              if (sipStack.isLoggingEnabled()) {
942                  sipStack.getStackLogger().logError(
943                          "Bad Dialog State for " + this + " dialogID = " + this.getDialogId());
944              }
945              throw new SipException("Bad dialog state " + this.getState());
946          }
947  
948          if (!this.getCallId().getCallId().equals(((SIPRequest) request).getCallId().getCallId())) {
949              if (sipStack.isLoggingEnabled()) {
950                  sipStack.getStackLogger().logError("CallID " + this.getCallId());
951                  sipStack.getStackLogger().logError(
952                          "RequestCallID = " + ackRequest.getCallId().getCallId());
953                  sipStack.getStackLogger().logError("dialog =  " + this);
954              }
955              throw new SipException("Bad call ID in request");
956          }
957          try {
958              if (sipStack.isLoggingEnabled()) {
959                  sipStack.getStackLogger().logDebug(
960                          "setting from tag For outgoing ACK= " + this.getLocalTag());
961                  sipStack.getStackLogger().logDebug(
962                          "setting To tag for outgoing ACK = " + this.getRemoteTag());
963                  sipStack.getStackLogger().logDebug("ack = " + ackRequest);
964              }
965              if (this.getLocalTag() != null)
966                  ackRequest.getFrom().setTag(this.getLocalTag());
967              if (this.getRemoteTag() != null)
968                  ackRequest.getTo().setTag(this.getRemoteTag());
969          } catch (ParseException ex) {
970              throw new SipException(ex.getMessage());
971          }
972  
973          Hop hop = sipStack.getNextHop(ackRequest);
974          // Hop hop = defaultRouter.getNextHop(ackRequest);
975          if (hop == null)
976              throw new SipException("No route!");
977          try {
978              if (sipStack.isLoggingEnabled())
979                  sipStack.getStackLogger().logDebug("hop = " + hop);
980              ListeningPointImpl lp = (ListeningPointImpl) this.sipProvider.getListeningPoint(hop
981                      .getTransport());
982              if (lp == null)
983                  throw new SipException("No listening point for this provider registered at "
984                          + hop);
985              InetAddress inetAddress = InetAddress.getByName(hop.getHost());
986              MessageChannel messageChannel = lp.getMessageProcessor().createMessageChannel(
987                      inetAddress, hop.getPort());
988              boolean releaseAckSem = false;
989              long cseqNo = ((SIPRequest)request).getCSeq().getSeqNumber();
990              if (!this.isAckSent(cseqNo)) {
991                  releaseAckSem = true;
992              }
993  
994              this.setLastAckSent(ackRequest);
995              messageChannel.sendMessage(ackRequest);
996              // Sent atleast one ACK.
997              this.isAcknowledged = true;
998              this.highestSequenceNumberAcknowledged = Math.max(this.highestSequenceNumberAcknowledged,
999                      ((SIPRequest)ackRequest).getCSeq().getSeqNumber());
1000              if (releaseAckSem && this.isBackToBackUserAgent) {
1001                  this.releaseAckSem();
1002              } else {
1003                  if ( sipStack.isLoggingEnabled() ) {
1004                      sipStack.getStackLogger().logDebug("Not releasing ack sem for " + this + " isAckSent " + releaseAckSem );
1005                  }
1006              }
1007          } catch (IOException ex) {
1008              if (throwIOExceptionAsSipException)
1009                  throw new SipException("Could not send ack", ex);
1010              this.raiseIOException(hop.getHost(), hop.getPort(), hop.getTransport());
1011          } catch (SipException ex) {
1012              if (sipStack.isLoggingEnabled())
1013                  sipStack.getStackLogger().logException(ex);
1014              throw ex;
1015          } catch (Exception ex) {
1016              if (sipStack.isLoggingEnabled())
1017                  sipStack.getStackLogger().logException(ex);
1018              throw new SipException("Could not create message channel", ex);
1019          }
1020          if (this.dialogDeleteTask != null) {
1021              this.dialogDeleteTask.cancel();
1022              this.dialogDeleteTask = null;
1023          }
1024          this.ackSeen = true;
1025  
1026      }
1027  
1028      // /////////////////////////////////////////////////////////////
1029      // Package local methods
1030      // /////////////////////////////////////////////////////////////
1031  
1032      /**
1033       * Set the stack address. Prevent us from routing messages to ourselves.
1034       *
1035       * @param sipStack the address of the SIP stack.
1036       *
1037       */
setStack(SIPTransactionStack sipStack)1038      void setStack(SIPTransactionStack sipStack) {
1039          this.sipStack = sipStack;
1040  
1041      }
1042  
1043      /**
1044       * Get the stack .
1045       *
1046       * @return sipStack the SIP stack of the dialog.
1047       *
1048       */
getStack()1049      SIPTransactionStack getStack() {
1050          return sipStack;
1051      }
1052  
1053      /**
1054       * Return True if this dialog is terminated on BYE.
1055       *
1056       */
isTerminatedOnBye()1057      boolean isTerminatedOnBye() {
1058  
1059          return this.terminateOnBye;
1060      }
1061  
1062      /**
1063       * Mark that the dialog has seen an ACK.
1064       */
ackReceived(SIPRequest sipRequest)1065      void ackReceived(SIPRequest sipRequest) {
1066  
1067          // Suppress retransmission of the final response
1068          if (this.ackSeen)
1069              return;
1070          SIPServerTransaction tr = this.getInviteTransaction();
1071          if (tr != null) {
1072              if (tr.getCSeq() == sipRequest.getCSeq().getSeqNumber()) {
1073              	acquireTimerTaskSem();
1074              	try {
1075  	                if (this.timerTask != null) {
1076  	                	this.timerTask.cancel();
1077  		                this.timerTask = null;
1078  	                }
1079              	} finally {
1080              		releaseTimerTaskSem();
1081              	}
1082                  this.ackSeen = true;
1083                  if (this.dialogDeleteTask != null) {
1084                      this.dialogDeleteTask.cancel();
1085                      this.dialogDeleteTask = null;
1086                  }
1087                  this.setLastAckReceived(sipRequest);
1088                  if (sipStack.isLoggingEnabled()) {
1089                      sipStack.getStackLogger().logDebug(
1090                              "ackReceived for " + ((SIPTransaction) tr).getMethod());
1091                      this.ackLine = sipStack.getStackLogger().getLineCount();
1092                      this.printDebugInfo();
1093                  }
1094                  if (this.isBackToBackUserAgent) {
1095                      this.releaseAckSem();
1096                  }
1097                  this.setState(CONFIRMED_STATE);
1098              }
1099          }
1100      }
1101  
1102      /**
1103       * Return true if a terminated event was delivered to the application as a result of the
1104       * dialog termination.
1105       *
1106       */
testAndSetIsDialogTerminatedEventDelivered()1107      synchronized boolean testAndSetIsDialogTerminatedEventDelivered() {
1108          boolean retval = this.dialogTerminatedEventDelivered;
1109          this.dialogTerminatedEventDelivered = true;
1110          return retval;
1111      }
1112  
1113      // /////////////////////////////////////////////////////////
1114      // Public methods
1115      // /////////////////////////////////////////////////////////
1116  
1117      /**
1118  	 * Adds a new event listener to this dialog.
1119  	 *
1120  	 * @param newListener
1121  	 *            Listener to add.
1122  	 */
addEventListener(SIPDialogEventListener newListener)1123  	public void addEventListener(SIPDialogEventListener newListener) {
1124  		eventListeners.add(newListener);
1125  	}
1126  
1127  	/**
1128  	 * Removed an event listener from this dialog.
1129  	 *
1130  	 * @param oldListener
1131  	 *            Listener to remove.
1132  	 */
removeEventListener(SIPDialogEventListener oldListener)1133  	public void removeEventListener(SIPDialogEventListener oldListener) {
1134  		eventListeners.remove(oldListener);
1135  	}
1136  
1137      /*
1138       * @see javax.sip.Dialog#setApplicationData()
1139       */
setApplicationData(Object applicationData)1140      public void setApplicationData(Object applicationData) {
1141          this.applicationData = applicationData;
1142      }
1143  
1144      /*
1145       * (non-Javadoc)
1146       *
1147       * @see javax.sip.Dialog#getApplicationData()
1148       */
getApplicationData()1149      public Object getApplicationData() {
1150          return this.applicationData;
1151      }
1152  
1153      /**
1154       * Updates the next consumable seqno.
1155       *
1156       */
requestConsumed()1157      public synchronized void requestConsumed() {
1158          this.nextSeqno = Long.valueOf(this.getRemoteSeqNumber() + 1);
1159  
1160          if (sipStack.isLoggingEnabled()) {
1161              this.sipStack.getStackLogger().logDebug(
1162                      "Request Consumed -- next consumable Request Seqno = " + this.nextSeqno);
1163          }
1164  
1165      }
1166  
1167      /**
1168       * Return true if this request can be consumed by the dialog.
1169       *
1170       * @param dialogRequest is the request to check with the dialog.
1171       * @return true if the dialogRequest sequence number matches the next consumable seqno.
1172       */
isRequestConsumable(SIPRequest dialogRequest)1173      public synchronized boolean isRequestConsumable(SIPRequest dialogRequest) {
1174          // have not yet set remote seqno - this is a fresh
1175          if (dialogRequest.getMethod().equals(Request.ACK))
1176              throw new RuntimeException("Illegal method");
1177  
1178          // For loose validation this function is delegated to the application
1179          if (!this.isSequnceNumberValidation()) {
1180              return true;
1181          }
1182  
1183          // JvB: Acceptable iff remoteCSeq < cseq. remoteCSeq==-1
1184          // when not defined yet, so that works too
1185          return remoteSequenceNumber < dialogRequest.getCSeq().getSeqNumber();
1186      }
1187  
1188      /**
1189       * This method is called when a forked dialog is created from the client side. It starts a
1190       * timer task. If the timer task expires before an ACK is sent then the dialog is cancelled
1191       * (i.e. garbage collected ).
1192       *
1193       */
doDeferredDelete()1194      public void doDeferredDelete() {
1195          if (sipStack.getTimer() == null)
1196              this.setState(TERMINATED_STATE);
1197          else {
1198              this.dialogDeleteTask = new DialogDeleteTask();
1199              // Delete the transaction after the max ack timeout.
1200              sipStack.getTimer().schedule(this.dialogDeleteTask,
1201                      SIPTransaction.TIMER_H * SIPTransactionStack.BASE_TIMER_INTERVAL);
1202          }
1203  
1204      }
1205  
1206      /**
1207       * Set the state for this dialog.
1208       *
1209       * @param state is the state to set for the dialog.
1210       */
1211  
setState(int state)1212      public void setState(int state) {
1213          if (sipStack.isLoggingEnabled()) {
1214              sipStack.getStackLogger().logDebug(
1215                      "Setting dialog state for " + this + "newState = " + state);
1216              sipStack.getStackLogger().logStackTrace();
1217              if (state != NULL_STATE && state != this.dialogState)
1218                  if (sipStack.isLoggingEnabled()) {
1219                      sipStack.getStackLogger().logDebug(
1220                              this + "  old dialog state is " + this.getState());
1221                      sipStack.getStackLogger().logDebug(
1222                              this + "  New dialog state is " + DialogState.getObject(state));
1223                  }
1224  
1225          }
1226          this.dialogState = state;
1227          // Dialog is in terminated state set it up for GC.
1228          if (state == TERMINATED_STATE) {
1229              if (sipStack.getTimer() != null) { // may be null after shutdown
1230                  sipStack.getTimer().schedule(new LingerTimer(), DIALOG_LINGER_TIME * 1000);
1231              }
1232              this.stopTimer();
1233  
1234          }
1235      }
1236  
1237      /**
1238       * Debugging print for the dialog.
1239       */
printDebugInfo()1240      public void printDebugInfo() {
1241          if (sipStack.isLoggingEnabled()) {
1242              sipStack.getStackLogger().logDebug("isServer = " + isServer());
1243              sipStack.getStackLogger().logDebug("localTag = " + getLocalTag());
1244              sipStack.getStackLogger().logDebug("remoteTag = " + getRemoteTag());
1245              sipStack.getStackLogger().logDebug("localSequenceNumer = " + getLocalSeqNumber());
1246              sipStack.getStackLogger().logDebug("remoteSequenceNumer = " + getRemoteSeqNumber());
1247              sipStack.getStackLogger().logDebug("ackLine:" + this.getRemoteTag() + " " + ackLine);
1248          }
1249      }
1250  
1251      /**
1252       * Return true if the dialog has already seen the ack.
1253       *
1254       * @return flag that records if the ack has been seen.
1255       */
isAckSeen()1256      public boolean isAckSeen() {
1257          return this.ackSeen;
1258      }
1259  
1260      /**
1261       * Get the last ACK for this transaction.
1262       */
getLastAckSent()1263      public SIPRequest getLastAckSent() {
1264          return this.lastAckSent;
1265      }
1266  
1267      /**
1268       * Return true if ACK was sent ( for client tx ). For server tx, this is a NO-OP ( we dont
1269       * send ACK).
1270       */
isAckSent(long cseqNo)1271      public boolean isAckSent(long cseqNo) {
1272          if (this.getLastTransaction() == null)
1273              return true;
1274          if (this.getLastTransaction() instanceof ClientTransaction) {
1275              if (this.getLastAckSent() == null) {
1276                  return false;
1277              } else {
1278                  return cseqNo <=((SIPRequest) this.getLastAckSent()).getCSeq().getSeqNumber();
1279              }
1280          } else {
1281              return true;
1282          }
1283      }
1284  
1285      /**
1286       * Get the transaction that created this dialog.
1287       */
getFirstTransaction()1288      public Transaction getFirstTransaction() {
1289          return this.firstTransaction;
1290      }
1291  
1292  
1293      /**
1294       * Gets the route set for the dialog. When acting as an User Agent Server the route set MUST
1295       * be set to the list of URIs in the Record-Route header field from the request, taken in
1296       * order and preserving all URI parameters. When acting as an User Agent Client the route set
1297       * MUST be set to the list of URIs in the Record-Route header field from the response, taken
1298       * in reverse order and preserving all URI parameters. If no Record-Route header field is
1299       * present in the request or response, the route set MUST be set to the empty set. This route
1300       * set, even if empty, overrides any pre-existing route set for future requests in this
1301       * dialog.
1302       * <p>
1303       * Requests within a dialog MAY contain Record-Route and Contact header fields. However, these
1304       * requests do not cause the dialog's route set to be modified.
1305       * <p>
1306       * The User Agent Client uses the remote target and route set to build the Request-URI and
1307       * Route header field of the request.
1308       *
1309       * @return an Iterator containing a list of route headers to be used for forwarding. Empty
1310       *         iterator is returned if route has not been established.
1311       */
getRouteSet()1312      public Iterator getRouteSet() {
1313          if (this.routeList == null) {
1314              return new LinkedList().listIterator();
1315          } else {
1316              return this.getRouteList().listIterator();
1317          }
1318      }
1319  
1320      /**
1321       * Add a Route list extracted from a SIPRequest to this Dialog.
1322       *
1323       * @param sipRequest
1324       */
addRoute(SIPRequest sipRequest)1325      public synchronized void addRoute(SIPRequest sipRequest) {
1326          if (sipStack.isLoggingEnabled()) {
1327              sipStack.getStackLogger().logDebug(
1328                      "setContact: dialogState: " + this + "state = " + this.getState());
1329          }
1330  
1331          if (this.dialogState == CONFIRMED_STATE
1332                  && SIPRequest.isTargetRefresh(sipRequest.getMethod())) {
1333              this.doTargetRefresh(sipRequest);
1334          }
1335          if (this.dialogState == CONFIRMED_STATE || this.dialogState == TERMINATED_STATE) {
1336              return;
1337          }
1338  
1339          // Fix for issue #225: mustn't learn Route set from mid-dialog requests
1340          if ( sipRequest.getToTag()!=null ) return;
1341  
1342          // Incoming Request has the route list
1343          RecordRouteList rrlist = sipRequest.getRecordRouteHeaders();
1344          // Add the route set from the incoming response in reverse
1345          // order
1346          if (rrlist != null) {
1347              this.addRoute(rrlist);
1348          } else {
1349              // Set the rotue list to the last seen route list.
1350              this.routeList = new RouteList();
1351          }
1352  
1353          // put the contact header from the incoming request into
1354          // the route set. JvB: some duplication here, ref. doTargetRefresh
1355          ContactList contactList = sipRequest.getContactHeaders();
1356          if (contactList != null) {
1357              this.setRemoteTarget((ContactHeader) contactList.getFirst());
1358          }
1359      }
1360  
1361      /**
1362       * Set the dialog identifier.
1363       */
setDialogId(String dialogId)1364      public void setDialogId(String dialogId) {
1365          this.dialogId = dialogId;
1366      }
1367  
1368      /**
1369       * Creates a new dialog based on a received NOTIFY. The dialog state is initialized
1370       * appropriately. The NOTIFY differs in the From tag
1371       *
1372       * Made this a separate method to clearly distinguish what's happening here - this is a
1373       * non-trivial case
1374       *
1375       * @param subscribeTx - the transaction started with the SUBSCRIBE that we sent
1376       * @param notifyST - the ServerTransaction created for an incoming NOTIFY
1377       * @return -- a new dialog created from the subscribe original SUBSCRIBE transaction.
1378       *
1379       *
1380       */
createFromNOTIFY(SIPClientTransaction subscribeTx, SIPTransaction notifyST)1381      public static SIPDialog createFromNOTIFY(SIPClientTransaction subscribeTx,
1382              SIPTransaction notifyST) {
1383          SIPDialog d = new SIPDialog(notifyST);
1384          //
1385          // The above sets d.firstTransaction to NOTIFY (ST), correct that
1386          //
1387          d.serverTransactionFlag = false;
1388          // they share this one
1389          d.lastTransaction = subscribeTx;
1390          storeFirstTransactionInfo(d, subscribeTx);
1391          d.terminateOnBye = false;
1392          d.localSequenceNumber = subscribeTx.getCSeq();
1393          SIPRequest not = (SIPRequest) notifyST.getRequest();
1394          d.remoteSequenceNumber = not.getCSeq().getSeqNumber();
1395          d.setDialogId(not.getDialogId(true));
1396          d.setLocalTag(not.getToTag());
1397          d.setRemoteTag(not.getFromTag());
1398          // to properly create the Dialog object.
1399          // If not the stack will throw an exception when creating the response.
1400          d.setLastResponse(subscribeTx, subscribeTx.getLastResponse());
1401  
1402          // Dont use setLocal / setRemote here, they make other assumptions
1403          d.localParty = not.getTo().getAddress();
1404          d.remoteParty = not.getFrom().getAddress();
1405  
1406          // initialize d's route set based on the NOTIFY. Any proxies must have
1407          // Record-Routed
1408          d.addRoute(not);
1409          d.setState(CONFIRMED_STATE); // set state, *after* setting route set!
1410          return d;
1411      }
1412  
1413      /**
1414       * Return true if is server.
1415       *
1416       * @return true if is server transaction created this dialog.
1417       */
isServer()1418      public boolean isServer() {
1419          if (this.firstTransactionSeen == false)
1420              return this.serverTransactionFlag;
1421          else
1422              return this.firstTransactionIsServerTransaction;
1423  
1424      }
1425  
1426      /**
1427       * Return true if this is a re-establishment of the dialog.
1428       *
1429       * @return true if the reInvite flag is set.
1430       */
isReInvite()1431      protected boolean isReInvite() {
1432          return this.reInviteFlag;
1433      }
1434  
1435      /**
1436       * Get the id for this dialog.
1437       *
1438       * @return the string identifier for this dialog.
1439       *
1440       */
getDialogId()1441      public String getDialogId() {
1442  
1443          if (this.dialogId == null && this.lastResponse != null)
1444              this.dialogId = this.lastResponse.getDialogId(isServer());
1445  
1446          return this.dialogId;
1447      }
1448  
storeFirstTransactionInfo(SIPDialog dialog, SIPTransaction transaction)1449      private static void storeFirstTransactionInfo(SIPDialog dialog, SIPTransaction transaction) {
1450      	dialog.firstTransaction = transaction;
1451      	dialog.firstTransactionSeen = true;
1452      	dialog.firstTransactionIsServerTransaction = transaction.isServerTransaction();
1453      	dialog.firstTransactionSecure = transaction.getRequest().getRequestURI().getScheme()
1454          	.equalsIgnoreCase("sips");
1455      	dialog.firstTransactionPort = transaction.getPort();
1456      	dialog.firstTransactionId = transaction.getBranchId();
1457      	dialog.firstTransactionMethod = transaction.getMethod();
1458  
1459          if (dialog.isServer()) {
1460              SIPServerTransaction st = (SIPServerTransaction) transaction;
1461              SIPResponse response = st.getLastResponse();
1462              dialog.contactHeader = response != null ? response.getContactHeader() : null;
1463          } else {
1464              SIPClientTransaction ct = (SIPClientTransaction) transaction;
1465              if (ct != null){
1466              	SIPRequest sipRequest = ct.getOriginalRequest();
1467              	dialog.contactHeader = sipRequest.getContactHeader();
1468              }
1469          }
1470      }
1471      /**
1472       * Add a transaction record to the dialog.
1473       *
1474       * @param transaction is the transaction to add to the dialog.
1475       */
addTransaction(SIPTransaction transaction)1476      public void addTransaction(SIPTransaction transaction) {
1477  
1478          SIPRequest sipRequest = (SIPRequest) transaction.getOriginalRequest();
1479  
1480          // Proessing a re-invite.
1481          if (firstTransactionSeen && !firstTransactionId.equals(transaction.getBranchId())
1482                  && transaction.getMethod().equals(firstTransactionMethod)) {
1483              this.reInviteFlag = true;
1484          }
1485  
1486          if (firstTransactionSeen == false) {
1487              // Record the local and remote sequenc
1488              // numbers and the from and to tags for future
1489              // use on this dialog.
1490          	storeFirstTransactionInfo(this, transaction);
1491              if (sipRequest.getMethod().equals(Request.SUBSCRIBE))
1492                  this.eventHeader = (EventHeader) sipRequest.getHeader(EventHeader.NAME);
1493  
1494              this.setLocalParty(sipRequest);
1495              this.setRemoteParty(sipRequest);
1496              this.setCallId(sipRequest);
1497              if (this.originalRequest == null) {
1498                  this.originalRequest = sipRequest;
1499              }
1500              if (this.method == null) {
1501                  this.method = sipRequest.getMethod();
1502              }
1503  
1504              if (transaction instanceof SIPServerTransaction) {
1505                  this.hisTag = sipRequest.getFrom().getTag();
1506                  // My tag is assigned when sending response
1507              } else {
1508                  setLocalSequenceNumber(sipRequest.getCSeq().getSeqNumber());
1509                  this.originalLocalSequenceNumber = localSequenceNumber;
1510                  this.myTag = sipRequest.getFrom().getTag();
1511                  if (myTag == null)
1512                  	if (sipStack.isLoggingEnabled())
1513                  		sipStack.getStackLogger().logError(
1514                              "The request's From header is missing the required Tag parameter.");
1515              }
1516          } else if (transaction.getMethod().equals(firstTransactionMethod)
1517                  && firstTransactionIsServerTransaction != transaction.isServerTransaction()) {
1518              // This case occurs when you are processing a re-invite.
1519              // Switch from client side to server side for re-invite
1520              // (put the other side on hold).
1521  
1522  			storeFirstTransactionInfo(this, transaction);
1523  
1524              this.setLocalParty(sipRequest);
1525              this.setRemoteParty(sipRequest);
1526              this.setCallId(sipRequest);
1527              this.originalRequest = sipRequest;
1528              this.method = sipRequest.getMethod();
1529  
1530          }
1531          if (transaction instanceof SIPServerTransaction)
1532              setRemoteSequenceNumber(sipRequest.getCSeq().getSeqNumber());
1533  
1534          // If this is a server transaction record the remote
1535          // sequence number to avoid re-processing of requests
1536          // with the same sequence number directed towards this
1537          // dialog.
1538  
1539          this.lastTransaction = transaction;
1540          // set a back ptr in the incoming dialog.
1541          // CHECKME -- why is this here?
1542          // transaction.setDialog(this,sipRequest);
1543          if (sipStack.isLoggingEnabled()) {
1544              sipStack.getStackLogger()
1545                      .logDebug("Transaction Added " + this + myTag + "/" + hisTag);
1546              sipStack.getStackLogger().logDebug(
1547                      "TID = " + transaction.getTransactionId() + "/"
1548                              + transaction.isServerTransaction());
1549              sipStack.getStackLogger().logStackTrace();
1550          }
1551      }
1552  
1553      /**
1554       * Set the remote tag.
1555       *
1556       * @param hisTag is the remote tag to set.
1557       */
setRemoteTag(String hisTag)1558      private void setRemoteTag(String hisTag) {
1559          if (sipStack.isLoggingEnabled()) {
1560              sipStack.getStackLogger().logDebug(
1561                      "setRemoteTag(): " + this + " remoteTag = " + this.hisTag + " new tag = "
1562                              + hisTag);
1563          }
1564          if (this.hisTag != null && hisTag != null && !hisTag.equals(this.hisTag)) {
1565              if (this.getState() != DialogState.EARLY) {
1566              	if (sipStack.isLoggingEnabled())
1567              		sipStack.getStackLogger().logDebug(
1568                          "Dialog is already established -- ignoring remote tag re-assignment");
1569                  return;
1570              } else if (sipStack.isRemoteTagReassignmentAllowed()) {
1571              	if (sipStack.isLoggingEnabled())
1572              		sipStack.getStackLogger().logDebug(
1573                          "UNSAFE OPERATION !  tag re-assignment " + this.hisTag
1574                                  + " trying to set to " + hisTag
1575                                  + " can cause unexpected effects ");
1576                  boolean removed = false;
1577                  if (this.sipStack.getDialog(dialogId) == this) {
1578                      this.sipStack.removeDialog(dialogId);
1579                      removed = true;
1580  
1581                  }
1582                  // Force recomputation of Dialog ID;
1583                  this.dialogId = null;
1584                  this.hisTag = hisTag;
1585                  if (removed) {
1586                  	if (sipStack.isLoggingEnabled())
1587                  		sipStack.getStackLogger().logDebug("ReInserting Dialog");
1588                      this.sipStack.putDialog(this);
1589                  }
1590              }
1591          } else {
1592              if (hisTag != null) {
1593                  this.hisTag = hisTag;
1594              } else {
1595              	if (sipStack.isLoggingEnabled())
1596              		sipStack.getStackLogger().logWarning("setRemoteTag : called with null argument ");
1597              }
1598          }
1599      }
1600  
1601      /**
1602       * Get the last transaction from the dialog.
1603       */
getLastTransaction()1604      public SIPTransaction getLastTransaction() {
1605          return this.lastTransaction;
1606      }
1607  
1608      /**
1609       * Get the INVITE transaction (null if no invite transaction).
1610       */
getInviteTransaction()1611      public SIPServerTransaction getInviteTransaction() {
1612          DialogTimerTask t = this.timerTask;
1613          if (t != null)
1614              return t.transaction;
1615          else
1616              return null;
1617      }
1618  
1619      /**
1620       * Set the local sequece number for the dialog (defaults to 1 when the dialog is created).
1621       *
1622       * @param lCseq is the local cseq number.
1623       *
1624       */
setLocalSequenceNumber(long lCseq)1625      private void setLocalSequenceNumber(long lCseq) {
1626          if (sipStack.isLoggingEnabled())
1627              sipStack.getStackLogger().logDebug(
1628                      "setLocalSequenceNumber: original  " + this.localSequenceNumber + " new  = "
1629                              + lCseq);
1630          if (lCseq <= this.localSequenceNumber)
1631              throw new RuntimeException("Sequence number should not decrease !");
1632          this.localSequenceNumber = lCseq;
1633      }
1634  
1635      /**
1636       * Set the remote sequence number for the dialog.
1637       *
1638       * @param rCseq is the remote cseq number.
1639       *
1640       */
setRemoteSequenceNumber(long rCseq)1641      public void setRemoteSequenceNumber(long rCseq) {
1642          if (sipStack.isLoggingEnabled())
1643              sipStack.getStackLogger().logDebug("setRemoteSeqno " + this + "/" + rCseq);
1644          this.remoteSequenceNumber = rCseq;
1645      }
1646  
1647      /**
1648       * Increment the local CSeq # for the dialog. This is useful for if you want to create a hole
1649       * in the sequence number i.e. route a request outside the dialog and then resume within the
1650       * dialog.
1651       */
incrementLocalSequenceNumber()1652      public void incrementLocalSequenceNumber() {
1653          ++this.localSequenceNumber;
1654      }
1655  
1656      /**
1657       * Get the remote sequence number (for cseq assignment of outgoing requests within this
1658       * dialog).
1659       *
1660       * @deprecated
1661       * @return local sequence number.
1662       */
1663  
getRemoteSequenceNumber()1664      public int getRemoteSequenceNumber() {
1665          return (int) this.remoteSequenceNumber;
1666      }
1667  
1668      /**
1669       * Get the local sequence number (for cseq assignment of outgoing requests within this
1670       * dialog).
1671       *
1672       * @deprecated
1673       * @return local sequence number.
1674       */
1675  
getLocalSequenceNumber()1676      public int getLocalSequenceNumber() {
1677          return (int) this.localSequenceNumber;
1678      }
1679  
1680      /**
1681       * Get the sequence number for the request that origianlly created the Dialog.
1682       *
1683       * @return -- the original starting sequence number for this dialog.
1684       */
getOriginalLocalSequenceNumber()1685      public long getOriginalLocalSequenceNumber() {
1686          return this.originalLocalSequenceNumber;
1687      }
1688  
1689      /*
1690       * (non-Javadoc)
1691       *
1692       * @see javax.sip.Dialog#getLocalSequenceNumberLong()
1693       */
getLocalSeqNumber()1694      public long getLocalSeqNumber() {
1695          return this.localSequenceNumber;
1696      }
1697  
1698      /*
1699       * (non-Javadoc)
1700       *
1701       * @see javax.sip.Dialog#getRemoteSequenceNumberLong()
1702       */
getRemoteSeqNumber()1703      public long getRemoteSeqNumber() {
1704          return this.remoteSequenceNumber;
1705      }
1706  
1707      /*
1708       * (non-Javadoc)
1709       *
1710       * @see javax.sip.Dialog#getLocalTag()
1711       */
getLocalTag()1712      public String getLocalTag() {
1713          return this.myTag;
1714      }
1715  
1716      /*
1717       * (non-Javadoc)
1718       *
1719       * @see javax.sip.Dialog#getRemoteTag()
1720       */
getRemoteTag()1721      public String getRemoteTag() {
1722  
1723          return hisTag;
1724      }
1725  
1726      /**
1727       * Set local tag for the transaction.
1728       *
1729       * @param mytag is the tag to use in From headers client transactions that belong to this
1730       *        dialog and for generating To tags for Server transaction requests that belong to
1731       *        this dialog.
1732       */
setLocalTag(String mytag)1733      private void setLocalTag(String mytag) {
1734          if (sipStack.isLoggingEnabled()) {
1735              sipStack.getStackLogger().logDebug("set Local tag " + mytag + " " + this.dialogId);
1736              sipStack.getStackLogger().logStackTrace();
1737          }
1738  
1739          this.myTag = mytag;
1740  
1741      }
1742  
1743      /*
1744       * (non-Javadoc)
1745       *
1746       * @see javax.sip.Dialog#delete()
1747       */
1748  
delete()1749      public void delete() {
1750          // the reaper will get him later.
1751          this.setState(TERMINATED_STATE);
1752      }
1753  
1754      /*
1755       * (non-Javadoc)
1756       *
1757       * @see javax.sip.Dialog#getCallId()
1758       */
getCallId()1759      public CallIdHeader getCallId() {
1760          return this.callIdHeader;
1761      }
1762  
1763      /**
1764       * set the call id header for this dialog.
1765       */
setCallId(SIPRequest sipRequest)1766      private void setCallId(SIPRequest sipRequest) {
1767          this.callIdHeader = sipRequest.getCallId();
1768      }
1769  
1770      /*
1771       * (non-Javadoc)
1772       *
1773       * @see javax.sip.Dialog#getLocalParty()
1774       */
1775  
getLocalParty()1776      public javax.sip.address.Address getLocalParty() {
1777          return this.localParty;
1778      }
1779  
setLocalParty(SIPMessage sipMessage)1780      private void setLocalParty(SIPMessage sipMessage) {
1781          if (!isServer()) {
1782              this.localParty = sipMessage.getFrom().getAddress();
1783          } else {
1784              this.localParty = sipMessage.getTo().getAddress();
1785          }
1786      }
1787  
1788      /**
1789       * Returns the Address identifying the remote party. This is the value of the To header of
1790       * locally initiated requests in this dialogue when acting as an User Agent Client.
1791       * <p>
1792       * This is the value of the From header of recieved responses in this dialogue when acting as
1793       * an User Agent Server.
1794       *
1795       * @return the address object of the remote party.
1796       */
getRemoteParty()1797      public javax.sip.address.Address getRemoteParty() {
1798  
1799          if (sipStack.isLoggingEnabled()) {
1800              sipStack.getStackLogger().logDebug("gettingRemoteParty " + this.remoteParty);
1801          }
1802          return this.remoteParty;
1803  
1804      }
1805  
1806      /*
1807       * (non-Javadoc)
1808       *
1809       * @see javax.sip.Dialog#getRemoteTarget()
1810       */
getRemoteTarget()1811      public javax.sip.address.Address getRemoteTarget() {
1812  
1813          return this.remoteTarget;
1814      }
1815  
1816      /*
1817       * (non-Javadoc)
1818       *
1819       * @see javax.sip.Dialog#getState()
1820       */
getState()1821      public DialogState getState() {
1822          if (this.dialogState == NULL_STATE)
1823              return null; // not yet initialized
1824          return DialogState.getObject(this.dialogState);
1825      }
1826  
1827      /**
1828       * Returns true if this Dialog is secure i.e. if the request arrived over TLS, and the
1829       * Request-URI contained a SIPS URI, the "secure" flag is set to TRUE.
1830       *
1831       * @return <code>true</code> if this dialogue was established using a sips URI over TLS, and
1832       *         <code>false</code> otherwise.
1833       */
isSecure()1834      public boolean isSecure() {
1835          return this.firstTransactionSecure;
1836      }
1837  
1838      /*
1839       * (non-Javadoc)
1840       *
1841       * @see javax.sip.Dialog#sendAck(javax.sip.message.Request)
1842       */
sendAck(Request request)1843      public void sendAck(Request request) throws SipException {
1844          this.sendAck(request, true);
1845      }
1846  
1847      /*
1848       * (non-Javadoc)
1849       *
1850       * @see javax.sip.Dialog#createRequest(java.lang.String)
1851       */
createRequest(String method)1852      public Request createRequest(String method) throws SipException {
1853  
1854          if (method.equals(Request.ACK) || method.equals(Request.PRACK)) {
1855              throw new SipException("Invalid method specified for createRequest:" + method);
1856          }
1857          if (lastResponse != null)
1858              return this.createRequest(method, this.lastResponse);
1859          else
1860              throw new SipException("Dialog not yet established -- no response!");
1861      }
1862  
1863      /**
1864       * The method that actually does the work of creating a request.
1865       *
1866       * @param method
1867       * @param response
1868       * @return
1869       * @throws SipException
1870       */
createRequest(String method, SIPResponse sipResponse)1871      private Request createRequest(String method, SIPResponse sipResponse) throws SipException {
1872          /*
1873           * Check if the dialog is in the right state (RFC 3261 section 15). The caller's UA MAY
1874           * send a BYE for either CONFIRMED or EARLY dialogs, and the callee's UA MAY send a BYE on
1875           * CONFIRMED dialogs, but MUST NOT send a BYE on EARLY dialogs.
1876           *
1877           * Throw out cancel request.
1878           */
1879  
1880          if (method == null || sipResponse == null)
1881              throw new NullPointerException("null argument");
1882  
1883          if (method.equals(Request.CANCEL))
1884              throw new SipException("Dialog.createRequest(): Invalid request");
1885  
1886          if (this.getState() == null
1887                  || (this.getState().getValue() == TERMINATED_STATE && !method
1888                          .equalsIgnoreCase(Request.BYE))
1889                  || (this.isServer() && this.getState().getValue() == EARLY_STATE && method
1890                          .equalsIgnoreCase(Request.BYE)))
1891              throw new SipException("Dialog  " + getDialogId()
1892                      + " not yet established or terminated " + this.getState());
1893  
1894          SipUri sipUri = null;
1895          if (this.getRemoteTarget() != null)
1896              sipUri = (SipUri) this.getRemoteTarget().getURI().clone();
1897          else {
1898              sipUri = (SipUri) this.getRemoteParty().getURI().clone();
1899              sipUri.clearUriParms();
1900          }
1901  
1902          CSeq cseq = new CSeq();
1903          try {
1904              cseq.setMethod(method);
1905              cseq.setSeqNumber(this.getLocalSeqNumber());
1906          } catch (Exception ex) {
1907          	if (sipStack.isLoggingEnabled())
1908          		sipStack.getStackLogger().logError("Unexpected error");
1909              InternalErrorHandler.handleException(ex);
1910          }
1911          /*
1912           * Add a via header for the outbound request based on the transport of the message
1913           * processor.
1914           */
1915  
1916          ListeningPointImpl lp = (ListeningPointImpl) this.sipProvider
1917                  .getListeningPoint(sipResponse.getTopmostVia().getTransport());
1918          if (lp == null) {
1919              if (sipStack.isLoggingEnabled())
1920                  sipStack.getStackLogger().logError(
1921                          "Cannot find listening point for transport "
1922                                  + sipResponse.getTopmostVia().getTransport());
1923              throw new SipException("Cannot find listening point for transport "
1924                      + sipResponse.getTopmostVia().getTransport());
1925          }
1926          Via via = lp.getViaHeader();
1927  
1928          From from = new From();
1929          from.setAddress(this.localParty);
1930          To to = new To();
1931          to.setAddress(this.remoteParty);
1932          SIPRequest sipRequest = sipResponse.createRequest(sipUri, via, cseq, from, to);
1933  
1934          /*
1935           * The default contact header is obtained from the provider. The application can override
1936           * this.
1937           *
1938           * JvB: Should only do this for target refresh requests, ie not for BYE, PRACK, etc
1939           */
1940  
1941          if (SIPRequest.isTargetRefresh(method)) {
1942              ContactHeader contactHeader = ((ListeningPointImpl) this.sipProvider
1943                      .getListeningPoint(lp.getTransport())).createContactHeader();
1944  
1945              ((SipURI) contactHeader.getAddress().getURI()).setSecure(this.isSecure());
1946              sipRequest.setHeader(contactHeader);
1947          }
1948  
1949          try {
1950              /*
1951               * Guess of local sequence number - this is being re-set when the request is actually
1952               * dispatched
1953               */
1954              cseq = (CSeq) sipRequest.getCSeq();
1955              cseq.setSeqNumber(this.localSequenceNumber + 1);
1956  
1957          } catch (InvalidArgumentException ex) {
1958              InternalErrorHandler.handleException(ex);
1959          }
1960  
1961          if (method.equals(Request.SUBSCRIBE)) {
1962  
1963              if (eventHeader != null)
1964                  sipRequest.addHeader(eventHeader);
1965  
1966          }
1967  
1968          /*
1969           * RFC3261, section 12.2.1.1:
1970           *
1971           * The URI in the To field of the request MUST be set to the remote URI from the dialog
1972           * state. The tag in the To header field of the request MUST be set to the remote tag of
1973           * the dialog ID. The From URI of the request MUST be set to the local URI from the dialog
1974           * state. The tag in the From header field of the request MUST be set to the local tag of
1975           * the dialog ID. If the value of the remote or local tags is null, the tag parameter MUST
1976           * be omitted from the To or From header fields, respectively.
1977           */
1978  
1979          try {
1980              if (this.getLocalTag() != null) {
1981                  from.setTag(this.getLocalTag());
1982              } else {
1983                  from.removeTag();
1984              }
1985              if (this.getRemoteTag() != null) {
1986                  to.setTag(this.getRemoteTag());
1987              } else {
1988                  to.removeTag();
1989              }
1990          } catch (ParseException ex) {
1991              InternalErrorHandler.handleException(ex);
1992          }
1993  
1994          // get the route list from the dialog.
1995          this.updateRequest(sipRequest);
1996  
1997          return sipRequest;
1998  
1999      }
2000  
2001      /*
2002       * (non-Javadoc)
2003       *
2004       * @see javax.sip.Dialog#sendRequest(javax.sip.ClientTransaction)
2005       */
2006  
sendRequest(ClientTransaction clientTransactionId)2007      public void sendRequest(ClientTransaction clientTransactionId)
2008              throws TransactionDoesNotExistException, SipException {
2009          this.sendRequest(clientTransactionId, !this.isBackToBackUserAgent);
2010      }
2011  
sendRequest(ClientTransaction clientTransactionId, boolean allowInterleaving)2012      public void sendRequest(ClientTransaction clientTransactionId, boolean allowInterleaving)
2013              throws TransactionDoesNotExistException, SipException {
2014  
2015          if ( (!allowInterleaving)
2016                  && clientTransactionId.getRequest().getMethod().equals(Request.INVITE)) {
2017              new Thread((new ReInviteSender(clientTransactionId))).start();
2018              return;
2019          }
2020  
2021          SIPRequest dialogRequest = ((SIPClientTransaction) clientTransactionId)
2022                  .getOriginalRequest();
2023  
2024          if (sipStack.isLoggingEnabled())
2025              sipStack.getStackLogger().logDebug(
2026                      "dialog.sendRequest " + " dialog = " + this + "\ndialogRequest = \n"
2027                              + dialogRequest);
2028  
2029          if (clientTransactionId == null)
2030              throw new NullPointerException("null parameter");
2031  
2032          if (dialogRequest.getMethod().equals(Request.ACK)
2033                  || dialogRequest.getMethod().equals(Request.CANCEL))
2034              throw new SipException("Bad Request Method. " + dialogRequest.getMethod());
2035  
2036          // JvB: added, allow re-sending of BYE after challenge
2037          if (byeSent && isTerminatedOnBye() && !dialogRequest.getMethod().equals(Request.BYE)) {
2038              if (sipStack.isLoggingEnabled())
2039                  sipStack.getStackLogger().logError("BYE already sent for " + this);
2040              throw new SipException("Cannot send request; BYE already sent");
2041          }
2042  
2043          if (dialogRequest.getTopmostVia() == null) {
2044              Via via = ((SIPClientTransaction) clientTransactionId).getOutgoingViaHeader();
2045              dialogRequest.addHeader(via);
2046          }
2047          if (!this.getCallId().getCallId().equalsIgnoreCase(dialogRequest.getCallId().getCallId())) {
2048  
2049              if (sipStack.isLoggingEnabled()) {
2050                  sipStack.getStackLogger().logError("CallID " + this.getCallId());
2051                  sipStack.getStackLogger().logError(
2052                          "RequestCallID = " + dialogRequest.getCallId().getCallId());
2053                  sipStack.getStackLogger().logError("dialog =  " + this);
2054              }
2055              throw new SipException("Bad call ID in request");
2056          }
2057  
2058          // Set the dialog back pointer.
2059          ((SIPClientTransaction) clientTransactionId).setDialog(this, this.dialogId);
2060  
2061          this.addTransaction((SIPTransaction) clientTransactionId);
2062          // Enable the retransmission filter for the transaction
2063  
2064          ((SIPClientTransaction) clientTransactionId).isMapped = true;
2065  
2066          From from = (From) dialogRequest.getFrom();
2067          To to = (To) dialogRequest.getTo();
2068  
2069          // Caller already did the tag assignment -- check to see if the
2070          // tag assignment is OK.
2071          if (this.getLocalTag() != null && from.getTag() != null
2072                  && !from.getTag().equals(this.getLocalTag()))
2073              throw new SipException("From tag mismatch expecting  " + this.getLocalTag());
2074  
2075          if (this.getRemoteTag() != null && to.getTag() != null
2076                  && !to.getTag().equals(this.getRemoteTag())) {
2077          	if (sipStack.isLoggingEnabled())
2078          		this.sipStack.getStackLogger().logWarning(
2079                      "To header tag mismatch expecting " + this.getRemoteTag());
2080          }
2081          /*
2082           * The application is sending a NOTIFY before sending the response of the dialog.
2083           */
2084          if (this.getLocalTag() == null && dialogRequest.getMethod().equals(Request.NOTIFY)) {
2085              if (!this.getMethod().equals(Request.SUBSCRIBE))
2086                  throw new SipException("Trying to send NOTIFY without SUBSCRIBE Dialog!");
2087              this.setLocalTag(from.getTag());
2088  
2089          }
2090  
2091          try {
2092              if (this.getLocalTag() != null)
2093                  from.setTag(this.getLocalTag());
2094              if (this.getRemoteTag() != null)
2095                  to.setTag(this.getRemoteTag());
2096  
2097          } catch (ParseException ex) {
2098  
2099              InternalErrorHandler.handleException(ex);
2100  
2101          }
2102  
2103          Hop hop = ((SIPClientTransaction) clientTransactionId).getNextHop();
2104          if (sipStack.isLoggingEnabled()) {
2105              sipStack.getStackLogger().logDebug(
2106                      "Using hop = " + hop.getHost() + " : " + hop.getPort());
2107          }
2108  
2109          try {
2110              MessageChannel messageChannel = sipStack.createRawMessageChannel(this
2111                      .getSipProvider().getListeningPoint(hop.getTransport()).getIPAddress(),
2112                      this.firstTransactionPort, hop);
2113  
2114              MessageChannel oldChannel = ((SIPClientTransaction)
2115              		clientTransactionId).getMessageChannel();
2116  
2117              // Remove this from the connection cache if it is in the
2118              // connection
2119              // cache and is not yet active.
2120              oldChannel.uncache();
2121  
2122              // Not configured to cache client connections.
2123              if (!sipStack.cacheClientConnections) {
2124                  oldChannel.useCount--;
2125                  if (sipStack.isLoggingEnabled())
2126                      sipStack.getStackLogger().logDebug(
2127                              "oldChannel: useCount " + oldChannel.useCount);
2128  
2129              }
2130  
2131              if (messageChannel == null) {
2132                  /*
2133                   * At this point the procedures of 8.1.2 and 12.2.1.1 of RFC3261 have been tried
2134                   * but the resulting next hop cannot be resolved (recall that the exception thrown
2135                   * is caught and ignored in SIPStack.createMessageChannel() so we end up here with
2136                   * a null messageChannel instead of the exception handler below). All else
2137                   * failing, try the outbound proxy in accordance with 8.1.2, in particular: This
2138                   * ensures that outbound proxies that do not add Record-Route header field values
2139                   * will drop out of the path of subsequent requests. It allows endpoints that
2140                   * cannot resolve the first Route URI to delegate that task to an outbound proxy.
2141                   *
2142                   * if one considers the 'first Route URI' of a request constructed according to
2143                   * 12.2.1.1 to be the request URI when the route set is empty.
2144                   */
2145                  if (sipStack.isLoggingEnabled())
2146                      sipStack.getStackLogger().logDebug(
2147                              "Null message channel using outbound proxy !");
2148                  Hop outboundProxy = sipStack.getRouter(dialogRequest).getOutboundProxy();
2149                  if (outboundProxy == null)
2150                      throw new SipException("No route found! hop=" + hop);
2151                  messageChannel = sipStack.createRawMessageChannel(this.getSipProvider()
2152                          .getListeningPoint(outboundProxy.getTransport()).getIPAddress(),
2153                          this.firstTransactionPort, outboundProxy);
2154                  if (messageChannel != null)
2155                      ((SIPClientTransaction) clientTransactionId)
2156                              .setEncapsulatedChannel(messageChannel);
2157              } else {
2158                  ((SIPClientTransaction) clientTransactionId)
2159                          .setEncapsulatedChannel(messageChannel);
2160  
2161                  if (sipStack.isLoggingEnabled()) {
2162                      sipStack.getStackLogger().logDebug("using message channel " + messageChannel);
2163  
2164                  }
2165  
2166              }
2167  
2168              if (messageChannel != null) messageChannel.useCount++;
2169  
2170              // See if we need to release the previously mapped channel.
2171              if ((!sipStack.cacheClientConnections) && oldChannel != null
2172                      && oldChannel.useCount <= 0)
2173                  oldChannel.close();
2174          } catch (Exception ex) {
2175              if (sipStack.isLoggingEnabled())
2176                  sipStack.getStackLogger().logException(ex);
2177              throw new SipException("Could not create message channel", ex);
2178          }
2179  
2180          try {
2181              // Increment before setting!!
2182              localSequenceNumber++;
2183              dialogRequest.getCSeq().setSeqNumber(getLocalSeqNumber());
2184          } catch (InvalidArgumentException ex) {
2185              sipStack.getStackLogger().logFatalError(ex.getMessage());
2186          }
2187  
2188          try {
2189              ((SIPClientTransaction) clientTransactionId).sendMessage(dialogRequest);
2190              /*
2191               * Note that if the BYE is rejected then the Dialog should bo back to the ESTABLISHED
2192               * state so we only set state after successful send.
2193               */
2194              if (dialogRequest.getMethod().equals(Request.BYE)) {
2195                  this.byeSent = true;
2196                  /*
2197                   * Dialog goes into TERMINATED state as soon as BYE is sent. ISSUE 182.
2198                   */
2199                  if (isTerminatedOnBye()) {
2200                      this.setState(DialogState._TERMINATED);
2201                  }
2202              }
2203          } catch (IOException ex) {
2204              throw new SipException("error sending message", ex);
2205          }
2206  
2207      }
2208  
2209      /**
2210       * Return yes if the last response is to be retransmitted.
2211       */
toRetransmitFinalResponse(int T2)2212      private boolean toRetransmitFinalResponse(int T2) {
2213          if (--retransmissionTicksLeft == 0) {
2214              if (2 * prevRetransmissionTicks <= T2)
2215                  this.retransmissionTicksLeft = 2 * prevRetransmissionTicks;
2216              else
2217                  this.retransmissionTicksLeft = prevRetransmissionTicks;
2218              this.prevRetransmissionTicks = retransmissionTicksLeft;
2219              return true;
2220          } else
2221              return false;
2222  
2223      }
2224  
setRetransmissionTicks()2225      protected void setRetransmissionTicks() {
2226          this.retransmissionTicksLeft = 1;
2227          this.prevRetransmissionTicks = 1;
2228      }
2229  
2230      /**
2231       * Resend the last ack.
2232       */
resendAck()2233      public void resendAck() throws SipException {
2234          // Check for null.
2235  
2236          if (this.getLastAckSent() != null) {
2237              if (getLastAckSent().getHeader(TimeStampHeader.NAME) != null
2238                      && sipStack.generateTimeStampHeader) {
2239                  TimeStamp ts = new TimeStamp();
2240                  try {
2241                      ts.setTimeStamp(System.currentTimeMillis());
2242                      getLastAckSent().setHeader(ts);
2243                  } catch (InvalidArgumentException e) {
2244  
2245                  }
2246              }
2247              this.sendAck(getLastAckSent(), false);
2248          }
2249  
2250      }
2251  
2252      /**
2253       * Get the method of the request/response that resulted in the creation of the Dialog.
2254       *
2255       * @return -- the method of the dialog.
2256       */
getMethod()2257      public String getMethod() {
2258          // Method of the request or response used to create this dialog
2259          return this.method;
2260      }
2261  
2262      /**
2263       * Start the dialog timer.
2264       *
2265       * @param transaction
2266       */
2267  
startTimer(SIPServerTransaction transaction)2268      protected void startTimer(SIPServerTransaction transaction) {
2269          if (this.timerTask != null && timerTask.transaction == transaction) {
2270          	if (sipStack.isLoggingEnabled())
2271          		sipStack.getStackLogger().logDebug("Timer already running for " + getDialogId());
2272              return;
2273          }
2274          if (sipStack.isLoggingEnabled())
2275              sipStack.getStackLogger().logDebug("Starting dialog timer for " + getDialogId());
2276          this.ackSeen = false;
2277  
2278  		acquireTimerTaskSem();
2279  		try {
2280  	        if (this.timerTask != null) {
2281  	            this.timerTask.transaction = transaction;
2282  	        } else {
2283  	            this.timerTask = new DialogTimerTask(transaction);
2284  	            sipStack.getTimer().schedule(timerTask, SIPTransactionStack.BASE_TIMER_INTERVAL,
2285  	                    SIPTransactionStack.BASE_TIMER_INTERVAL);
2286  	        }
2287  		} finally {
2288  			releaseTimerTaskSem();
2289  		}
2290  
2291          this.setRetransmissionTicks();
2292      }
2293  
2294      /**
2295       * Stop the dialog timer. This is called when the dialog is terminated.
2296       *
2297       */
stopTimer()2298      protected void stopTimer() {
2299          try {
2300          	acquireTimerTaskSem();
2301          	try {
2302  	            if (this.timerTask != null) {
2303  	            	this.timerTask.cancel();
2304  		            this.timerTask = null;
2305  	            }
2306          	} finally {
2307          		releaseTimerTaskSem();
2308          	}
2309          } catch (Exception ex) {
2310          }
2311      }
2312  
2313      /*
2314       * (non-Javadoc) Retransmissions of the reliable provisional response cease when a matching
2315       * PRACK is received by the UA core. PRACK is like any other request within a dialog, and the
2316       * UAS core processes it according to the procedures of Sections 8.2 and 12.2.2 of RFC 3261. A
2317       * matching PRACK is defined as one within the same dialog as the response, and whose method,
2318       * CSeq-num, and response-num in the RAck header field match, respectively, the method from
2319       * the CSeq, the sequence number from the CSeq, and the sequence number from the RSeq of the
2320       * reliable provisional response.
2321       *
2322       * @see javax.sip.Dialog#createPrack(javax.sip.message.Response)
2323       */
createPrack(Response relResponse)2324      public Request createPrack(Response relResponse) throws DialogDoesNotExistException,
2325              SipException {
2326  
2327          if (this.getState() == null || this.getState().equals(DialogState.TERMINATED))
2328              throw new DialogDoesNotExistException("Dialog not initialized or terminated");
2329  
2330          if ((RSeq) relResponse.getHeader(RSeqHeader.NAME) == null) {
2331              throw new SipException("Missing RSeq Header");
2332          }
2333  
2334          try {
2335              SIPResponse sipResponse = (SIPResponse) relResponse;
2336              SIPRequest sipRequest = (SIPRequest) this.createRequest(Request.PRACK,
2337                      (SIPResponse) relResponse);
2338              String toHeaderTag = sipResponse.getTo().getTag();
2339              sipRequest.setToTag(toHeaderTag);
2340              RAck rack = new RAck();
2341              RSeq rseq = (RSeq) relResponse.getHeader(RSeqHeader.NAME);
2342              rack.setMethod(sipResponse.getCSeq().getMethod());
2343              rack.setCSequenceNumber((int) sipResponse.getCSeq().getSeqNumber());
2344              rack.setRSequenceNumber(rseq.getSeqNumber());
2345              sipRequest.setHeader(rack);
2346              return (Request) sipRequest;
2347          } catch (Exception ex) {
2348              InternalErrorHandler.handleException(ex);
2349              return null;
2350          }
2351  
2352      }
2353  
updateRequest(SIPRequest sipRequest)2354      private void updateRequest(SIPRequest sipRequest) {
2355  
2356          RouteList rl = this.getRouteList();
2357          if (rl.size() > 0) {
2358              sipRequest.setHeader(rl);
2359          } else {
2360              sipRequest.removeHeader(RouteHeader.NAME);
2361          }
2362          if (MessageFactoryImpl.getDefaultUserAgentHeader() != null) {
2363              sipRequest.setHeader(MessageFactoryImpl.getDefaultUserAgentHeader());
2364          }
2365  
2366      }
2367  
2368      /*
2369       * (non-Javadoc) The UAC core MUST generate an ACK request for each 2xx received from the
2370       * transaction layer. The header fields of the ACK are constructed in the same way as for any
2371       * request sent within a dialog (see Section 12) with the exception of the CSeq and the header
2372       * fields related to authentication. The sequence number of the CSeq header field MUST be the
2373       * same as the INVITE being acknowledged, but the CSeq method MUST be ACK. The ACK MUST
2374       * contain the same credentials as the INVITE. If the 2xx contains an offer (based on the
2375       * rules above), the ACK MUST carry an answer in its body. If the offer in the 2xx response is
2376       * not acceptable, the UAC core MUST generate a valid answer in the ACK and then send a BYE
2377       * immediately.
2378       *
2379       * Note that for the case of forked requests, you can create multiple outgoing invites each
2380       * with a different cseq and hence you need to supply the invite.
2381       *
2382       * @see javax.sip.Dialog#createAck(long)
2383       */
createAck(long cseqno)2384      public Request createAck(long cseqno) throws InvalidArgumentException, SipException {
2385  
2386          // JvB: strictly speaking it is allowed to start a dialog with
2387          // SUBSCRIBE,
2388          // then send INVITE+ACK later on
2389          if (!method.equals(Request.INVITE))
2390              throw new SipException("Dialog was not created with an INVITE" + method);
2391  
2392          if (cseqno <= 0)
2393              throw new InvalidArgumentException("bad cseq <= 0 ");
2394          else if (cseqno > ((((long) 1) << 32) - 1))
2395              throw new InvalidArgumentException("bad cseq > " + ((((long) 1) << 32) - 1));
2396  
2397          if (this.remoteTarget == null) {
2398              throw new SipException("Cannot create ACK - no remote Target!");
2399          }
2400  
2401          if (this.sipStack.isLoggingEnabled()) {
2402              this.sipStack.getStackLogger().logDebug("createAck " + this + " cseqno " + cseqno);
2403          }
2404  
2405          // MUST ack in the same order that the OKs were received. This traps
2406          // out of order ACK sending. Old ACKs seqno's can always be ACKed.
2407          if (lastInviteOkReceived < cseqno) {
2408          	if (sipStack.isLoggingEnabled()) {
2409          		this.sipStack.getStackLogger().logDebug(
2410                      "WARNING : Attempt to crete ACK without OK " + this);
2411              	this.sipStack.getStackLogger().logDebug("LAST RESPONSE = " + this.lastResponse);
2412          	}
2413              throw new SipException("Dialog not yet established -- no OK response!");
2414          }
2415  
2416          try {
2417  
2418              // JvB: Transport from first entry in route set, or remote Contact
2419              // if none
2420              // Only used to find correct LP & create correct Via
2421              SipURI uri4transport = null;
2422  
2423              if (this.routeList != null && !this.routeList.isEmpty()) {
2424                  Route r = (Route) this.routeList.getFirst();
2425                  uri4transport = ((SipURI) r.getAddress().getURI());
2426              } else { // should be !=null, checked above
2427                  uri4transport = ((SipURI) this.remoteTarget.getURI());
2428              }
2429  
2430              String transport = uri4transport.getTransportParam();
2431              if (transport == null) {
2432                  // JvB fix: also support TLS
2433                  transport = uri4transport.isSecure() ? ListeningPoint.TLS : ListeningPoint.UDP;
2434              }
2435              ListeningPointImpl lp = (ListeningPointImpl) sipProvider.getListeningPoint(transport);
2436              if (lp == null) {
2437              	if (sipStack.isLoggingEnabled()) {
2438              		sipStack.getStackLogger().logError(
2439                          "remoteTargetURI " + this.remoteTarget.getURI());
2440                  	sipStack.getStackLogger().logError("uri4transport = " + uri4transport);
2441                  	sipStack.getStackLogger().logError("No LP found for transport=" + transport);
2442              	}
2443                  throw new SipException(
2444                          "Cannot create ACK - no ListeningPoint for transport towards next hop found:"
2445                                  + transport);
2446              }
2447              SIPRequest sipRequest = new SIPRequest();
2448              sipRequest.setMethod(Request.ACK);
2449              sipRequest.setRequestURI((SipUri) getRemoteTarget().getURI().clone());
2450              sipRequest.setCallId(this.callIdHeader);
2451              sipRequest.setCSeq(new CSeq(cseqno, Request.ACK));
2452              List<Via> vias = new ArrayList<Via>();
2453              // Via via = lp.getViaHeader();
2454              // The user may have touched the sentby for the response.
2455              // so use the via header extracted from the response for the ACK =>
2456              // https://jain-sip.dev.java.net/issues/show_bug.cgi?id=205
2457              // strip the params from the via of the response and use the params from the
2458              // original request
2459              Via via = this.lastResponse.getTopmostVia();
2460              via.removeParameters();
2461              if (originalRequest != null && originalRequest.getTopmostVia() != null) {
2462                  NameValueList originalRequestParameters = originalRequest.getTopmostVia()
2463                          .getParameters();
2464                  if (originalRequestParameters != null && originalRequestParameters.size() > 0) {
2465                      via.setParameters((NameValueList) originalRequestParameters.clone());
2466                  }
2467              }
2468              via.setBranch(Utils.getInstance().generateBranchId()); // new branch
2469              vias.add(via);
2470              sipRequest.setVia(vias);
2471              From from = new From();
2472              from.setAddress(this.localParty);
2473              from.setTag(this.myTag);
2474              sipRequest.setFrom(from);
2475              To to = new To();
2476              to.setAddress(this.remoteParty);
2477              if (hisTag != null)
2478                  to.setTag(this.hisTag);
2479              sipRequest.setTo(to);
2480              sipRequest.setMaxForwards(new MaxForwards(70));
2481  
2482              if (this.originalRequest != null) {
2483                  Authorization authorization = this.originalRequest.getAuthorization();
2484                  if (authorization != null)
2485                      sipRequest.setHeader(authorization);
2486              }
2487  
2488              // ACKs for 2xx responses
2489              // use the Route values learned from the Record-Route of the 2xx
2490              // responses.
2491              this.updateRequest(sipRequest);
2492  
2493              return sipRequest;
2494          } catch (Exception ex) {
2495              InternalErrorHandler.handleException(ex);
2496              throw new SipException("unexpected exception ", ex);
2497          }
2498  
2499      }
2500  
2501      /**
2502       * Get the provider for this Dialog.
2503       *
2504       * SPEC_REVISION
2505       *
2506       * @return -- the SIP Provider associated with this transaction.
2507       */
getSipProvider()2508      public SipProviderImpl getSipProvider() {
2509          return this.sipProvider;
2510      }
2511  
2512      /**
2513       * @param sipProvider the sipProvider to set
2514       */
setSipProvider(SipProviderImpl sipProvider)2515      public void setSipProvider(SipProviderImpl sipProvider) {
2516          this.sipProvider = sipProvider;
2517      }
2518  
2519      /**
2520       * Check the tags of the response against the tags of the Dialog. Return true if the respnse
2521       * matches the tags of the dialog. We do this check wehn sending out a response.
2522       *
2523       * @param sipResponse -- the response to check.
2524       *
2525       */
setResponseTags(SIPResponse sipResponse)2526      public void setResponseTags(SIPResponse sipResponse) {
2527          if (this.getLocalTag() != null || this.getRemoteTag() != null) {
2528              return;
2529          }
2530          String responseFromTag = sipResponse.getFromTag();
2531          if ( responseFromTag != null ) {
2532              if (responseFromTag.equals(this.getLocalTag())) {
2533                  sipResponse.setToTag(this.getRemoteTag());
2534              } else if (responseFromTag.equals(this.getRemoteTag())) {
2535                  sipResponse.setToTag(this.getLocalTag());
2536              }
2537          } else {
2538          	if (sipStack.isLoggingEnabled())
2539          		sipStack.getStackLogger().logWarning("No from tag in response! Not RFC 3261 compatible.");
2540          }
2541  
2542      }
2543  
2544      /**
2545       * Set the last response for this dialog. This method is called for updating the dialog state
2546       * when a response is either sent or received from within a Dialog.
2547       *
2548       * @param transaction -- the transaction associated with the response
2549       * @param sipResponse -- the last response to set.
2550       */
setLastResponse(SIPTransaction transaction, SIPResponse sipResponse)2551      public void setLastResponse(SIPTransaction transaction, SIPResponse sipResponse) {
2552          this.callIdHeader = sipResponse.getCallId();
2553          int statusCode = sipResponse.getStatusCode();
2554          if (statusCode == 100) {
2555          	if (sipStack.isLoggingEnabled())
2556          		sipStack.getStackLogger().logWarning(
2557                      "Invalid status code - 100 in setLastResponse - ignoring");
2558              return;
2559          }
2560  
2561          this.lastResponse = sipResponse;
2562          this.setAssigned();
2563          // Adjust state of the Dialog state machine.
2564          if (sipStack.isLoggingEnabled()) {
2565              sipStack.getStackLogger().logDebug(
2566                      "sipDialog: setLastResponse:" + this + " lastResponse = "
2567                              + this.lastResponse.getFirstLine());
2568          }
2569          if (this.getState() == DialogState.TERMINATED) {
2570              if (sipStack.isLoggingEnabled()) {
2571                  sipStack.getStackLogger().logDebug(
2572                          "sipDialog: setLastResponse -- dialog is terminated - ignoring ");
2573              }
2574              // Capture the OK response for later use in createAck
2575              // This is handy for late arriving OK's that we want to ACK.
2576              if (sipResponse.getCSeq().getMethod().equals(Request.INVITE) && statusCode == 200) {
2577  
2578                  this.lastInviteOkReceived = Math.max(sipResponse.getCSeq().getSeqNumber(),
2579                          this.lastInviteOkReceived);
2580              }
2581              return;
2582          }
2583          String cseqMethod = sipResponse.getCSeq().getMethod();
2584          if (sipStack.isLoggingEnabled()) {
2585              sipStack.getStackLogger().logStackTrace();
2586              sipStack.getStackLogger().logDebug("cseqMethod = " + cseqMethod);
2587              sipStack.getStackLogger().logDebug("dialogState = " + this.getState());
2588              sipStack.getStackLogger().logDebug("method = " + this.getMethod());
2589              sipStack.getStackLogger().logDebug("statusCode = " + statusCode);
2590              sipStack.getStackLogger().logDebug("transaction = " + transaction);
2591          }
2592  
2593          // JvB: don't use "!this.isServer" here
2594          // note that the transaction can be null for forked
2595          // responses.
2596          if (transaction == null || transaction instanceof ClientTransaction) {
2597              if (sipStack.isDialogCreated(cseqMethod)) {
2598                  // Make a final tag assignment.
2599                  if (getState() == null && (statusCode / 100 == 1)) {
2600                      /*
2601                       * Guard aginst slipping back into early state from confirmed state.
2602                       */
2603                      // Was (sipResponse.getToTag() != null || sipStack.rfc2543Supported)
2604                      setState(SIPDialog.EARLY_STATE);
2605                      if ((sipResponse.getToTag() != null || sipStack.rfc2543Supported)
2606                              && this.getRemoteTag() == null) {
2607                          setRemoteTag(sipResponse.getToTag());
2608                          this.setDialogId(sipResponse.getDialogId(false));
2609                          sipStack.putDialog(this);
2610                          this.addRoute(sipResponse);
2611                      }
2612                  } else if (getState() != null && getState().equals(DialogState.EARLY)
2613                          && statusCode / 100 == 1) {
2614                      /*
2615                       * This case occurs for forked dialog responses. The To tag can change as a
2616                       * result of the forking. The remote target can also change as a result of the
2617                       * forking.
2618                       */
2619                      if (cseqMethod.equals(getMethod()) && transaction != null
2620                              && (sipResponse.getToTag() != null || sipStack.rfc2543Supported)) {
2621                          setRemoteTag(sipResponse.getToTag());
2622                          this.setDialogId(sipResponse.getDialogId(false));
2623                          sipStack.putDialog(this);
2624                          this.addRoute(sipResponse);
2625                      }
2626                  } else if (statusCode / 100 == 2) {
2627                      // This is a dialog creating method (such as INVITE).
2628                      // 2xx response -- set the state to the confirmed
2629                      // state. To tag is MANDATORY for the response.
2630  
2631                      // Only do this if method equals initial request!
2632  
2633                      if (cseqMethod.equals(getMethod())
2634                              && (sipResponse.getToTag() != null || sipStack.rfc2543Supported)
2635                              && this.getState() != DialogState.CONFIRMED) {
2636                          setRemoteTag(sipResponse.getToTag());
2637                          this.setDialogId(sipResponse.getDialogId(false));
2638                          sipStack.putDialog(this);
2639                          this.addRoute(sipResponse);
2640  
2641                          setState(SIPDialog.CONFIRMED_STATE);
2642                      }
2643  
2644                      // Capture the OK response for later use in createAck
2645                      if (cseqMethod.equals(Request.INVITE)) {
2646                          this.lastInviteOkReceived = Math.max(sipResponse.getCSeq().getSeqNumber(),
2647                                  this.lastInviteOkReceived);
2648                      }
2649  
2650                  } else if (statusCode >= 300
2651                          && statusCode <= 699
2652                          && (getState() == null || (cseqMethod.equals(getMethod()) && getState()
2653                                  .getValue() == SIPDialog.EARLY_STATE))) {
2654                      /*
2655                       * This case handles 3xx, 4xx, 5xx and 6xx responses. RFC 3261 Section 12.3 -
2656                       * dialog termination. Independent of the method, if a request outside of a
2657                       * dialog generates a non-2xx final response, any early dialogs created
2658                       * through provisional responses to that request are terminated.
2659                       */
2660                      setState(SIPDialog.TERMINATED_STATE);
2661                  }
2662  
2663                  /*
2664                   * This code is in support of "proxy" servers that are constructed as back to back
2665                   * user agents. This could be a dialog in the middle of the call setup path
2666                   * somewhere. Hence the incoming invite has record route headers in it. The
2667                   * response will have additional record route headers. However, for this dialog
2668                   * only the downstream record route headers matter. Ideally proxy servers should
2669                   * not be constructed as Back to Back User Agents. Remove all the record routes
2670                   * that are present in the incoming INVITE so you only have the downstream Route
2671                   * headers present in the dialog. Note that for an endpoint - you will have no
2672                   * record route headers present in the original request so the loop will not
2673                   * execute.
2674                   */
2675                  if ( this.getState() != DialogState.CONFIRMED && this.getState() != DialogState.TERMINATED ) {
2676                      if (originalRequest != null) {
2677                          RecordRouteList rrList = originalRequest.getRecordRouteHeaders();
2678                          if (rrList != null) {
2679                              ListIterator<RecordRoute> it = rrList.listIterator(rrList.size());
2680                              while (it.hasPrevious()) {
2681                                  RecordRoute rr = (RecordRoute) it.previous();
2682                                  Route route = (Route) routeList.getFirst();
2683                                  if (route != null && rr.getAddress().equals(route.getAddress())) {
2684                                      routeList.removeFirst();
2685                                  } else
2686                                      break;
2687                              }
2688                          }
2689                      }
2690                  }
2691  
2692              } else if (cseqMethod.equals(Request.NOTIFY)
2693                      && (this.getMethod().equals(Request.SUBSCRIBE) || this.getMethod().equals(
2694                              Request.REFER)) && sipResponse.getStatusCode() / 100 == 2
2695                      && this.getState() == null) {
2696                  // This is a notify response.
2697                  this.setDialogId(sipResponse.getDialogId(true));
2698                  sipStack.putDialog(this);
2699                  this.setState(SIPDialog.CONFIRMED_STATE);
2700  
2701              } else if (cseqMethod.equals(Request.BYE) && statusCode / 100 == 2
2702                      && isTerminatedOnBye()) {
2703                  // Dialog will be terminated when the transction is terminated.
2704                  setState(SIPDialog.TERMINATED_STATE);
2705              }
2706          } else {
2707              // Processing Server Dialog.
2708  
2709              if (cseqMethod.equals(Request.BYE) && statusCode / 100 == 2
2710                      && this.isTerminatedOnBye()) {
2711                  /*
2712                   * Only transition to terminated state when 200 OK is returned for the BYE. Other
2713                   * status codes just result in leaving the state in COMPLETED state.
2714                   */
2715                  this.setState(SIPDialog.TERMINATED_STATE);
2716              } else {
2717                  boolean doPutDialog = false;
2718  
2719                  if (getLocalTag() == null && sipResponse.getTo().getTag() != null
2720                          && sipStack.isDialogCreated(cseqMethod) && cseqMethod.equals(getMethod())) {
2721                      setLocalTag(sipResponse.getTo().getTag());
2722  
2723                      doPutDialog = true;
2724                  }
2725  
2726                  if (statusCode / 100 != 2) {
2727                      if (statusCode / 100 == 1) {
2728                          if (doPutDialog) {
2729  
2730                              setState(SIPDialog.EARLY_STATE);
2731                              this.setDialogId(sipResponse.getDialogId(true));
2732                              sipStack.putDialog(this);
2733                          }
2734                      } else {
2735                          /*
2736                           * RFC 3265 chapter 3.1.4.1 "Non-200 class final responses indicate that
2737                           * no subscription or dialog has been created, and no subsequent NOTIFY
2738                           * message will be sent. All non-200 class" + responses (with the
2739                           * exception of "489", described herein) have the same meanings and
2740                           * handling as described in SIP"
2741                           */
2742                          // Bug Fix by Jens tinfors
2743                          // see https://jain-sip.dev.java.net/servlets/ReadMsg?list=users&msgNo=797
2744                          if (statusCode == 489
2745                                  && (cseqMethod.equals(Request.NOTIFY) || cseqMethod
2746                                          .equals(Request.SUBSCRIBE))) {
2747                          	if (sipStack.isLoggingEnabled())
2748                          		sipStack.getStackLogger().logDebug(
2749                                      "RFC 3265 : Not setting dialog to TERMINATED for 489");
2750                          } else {
2751                              // baranowb: simplest fix to
2752                              // https://jain-sip.dev.java.net/issues/show_bug.cgi?id=175
2753                              // application is responsible for terminating in this case
2754                              // see rfc 5057 for better explanation
2755                              if (!this.isReInvite() && getState() != DialogState.CONFIRMED) {
2756                                  this.setState(SIPDialog.TERMINATED_STATE);
2757                              }
2758                          }
2759                      }
2760  
2761                  } else {
2762  
2763                      /*
2764                       * JvB: RFC4235 says that when sending 2xx on UAS side, state should move to
2765                       * CONFIRMED
2766                       */
2767                      if (this.dialogState <= SIPDialog.EARLY_STATE
2768                              && (cseqMethod.equals(Request.INVITE)
2769                                      || cseqMethod.equals(Request.SUBSCRIBE) || cseqMethod
2770                                      .equals(Request.REFER))) {
2771                          this.setState(SIPDialog.CONFIRMED_STATE);
2772                      }
2773  
2774                      if (doPutDialog) {
2775                          this.setDialogId(sipResponse.getDialogId(true));
2776                          sipStack.putDialog(this);
2777                      }
2778                      /*
2779                       * We put the dialog into the table. We must wait for ACK before re-INVITE is
2780                       * sent
2781                       */
2782                      if (transaction.getState() != TransactionState.TERMINATED
2783                              && sipResponse.getStatusCode() == Response.OK
2784                              && cseqMethod.equals(Request.INVITE)
2785                              && this.isBackToBackUserAgent) {
2786                              /*
2787                               * Acquire the flag for re-INVITE so that we cannot re-INVITE before
2788                               * ACK is received.
2789                               */
2790                              if (!this.takeAckSem()) {
2791                                  if (sipStack.isLoggingEnabled()) {
2792                                      sipStack.getStackLogger().logDebug(
2793                                              "Delete dialog -- cannot acquire ackSem");
2794                                  }
2795                                  this.delete();
2796                                  return;
2797                              }
2798  
2799                      }
2800                  }
2801              }
2802  
2803          }
2804  
2805      }
2806  
2807      /**
2808       * Start the retransmit timer.
2809       *
2810       * @param sipServerTx -- server transaction on which the response was sent
2811       * @param response - response that was sent.
2812       */
startRetransmitTimer(SIPServerTransaction sipServerTx, Response response)2813      public void startRetransmitTimer(SIPServerTransaction sipServerTx, Response response) {
2814          if (sipServerTx.getRequest().getMethod().equals(Request.INVITE)
2815                  && response.getStatusCode() / 100 == 2) {
2816              this.startTimer(sipServerTx);
2817          }
2818      }
2819  
2820      /**
2821       * @return -- the last response associated with the dialog.
2822       */
getLastResponse()2823      public SIPResponse getLastResponse() {
2824  
2825          return lastResponse;
2826      }
2827  
2828      /**
2829       * Do taget refresh dialog state updates.
2830       *
2831       * RFC 3261: Requests within a dialog MAY contain Record-Route and Contact header fields.
2832       * However, these requests do not cause the dialog's route set to be modified, although they
2833       * may modify the remote target URI. Specifically, requests that are not target refresh
2834       * requests do not modify the dialog's remote target URI, and requests that are target refresh
2835       * requests do. For dialogs that have been established with an
2836       *
2837       * INVITE, the only target refresh request defined is re-INVITE (see Section 14). Other
2838       * extensions may define different target refresh requests for dialogs established in other
2839       * ways.
2840       */
doTargetRefresh(SIPMessage sipMessage)2841      private void doTargetRefresh(SIPMessage sipMessage) {
2842  
2843          ContactList contactList = sipMessage.getContactHeaders();
2844  
2845          /*
2846           * INVITE is the target refresh for INVITE dialogs. SUBSCRIBE is the target refresh for
2847           * subscribe dialogs from the client side. This modifies the remote target URI potentially
2848           */
2849          if (contactList != null) {
2850  
2851              Contact contact = (Contact) contactList.getFirst();
2852              this.setRemoteTarget(contact);
2853  
2854          }
2855  
2856      }
2857  
optionPresent(ListIterator l, String option)2858      private static final boolean optionPresent(ListIterator l, String option) {
2859          while (l.hasNext()) {
2860              OptionTag opt = (OptionTag) l.next();
2861              if (opt != null && option.equalsIgnoreCase(opt.getOptionTag()))
2862                  return true;
2863          }
2864          return false;
2865      }
2866  
2867      /*
2868       * (non-Javadoc)
2869       *
2870       * @see javax.sip.Dialog#createReliableProvisionalResponse(int)
2871       */
createReliableProvisionalResponse(int statusCode)2872      public Response createReliableProvisionalResponse(int statusCode)
2873              throws InvalidArgumentException, SipException {
2874  
2875          if (!(firstTransactionIsServerTransaction)) {
2876              throw new SipException("Not a Server Dialog!");
2877  
2878          }
2879          /*
2880           * A UAS MUST NOT attempt to send a 100 (Trying) response reliably. Only provisional
2881           * responses numbered 101 to 199 may be sent reliably. If the request did not include
2882           * either a Supported or Require header field indicating this feature, the UAS MUST NOT
2883           * send the provisional response reliably.
2884           */
2885          if (statusCode <= 100 || statusCode > 199)
2886              throw new InvalidArgumentException("Bad status code ");
2887          SIPRequest request = this.originalRequest;
2888          if (!request.getMethod().equals(Request.INVITE))
2889              throw new SipException("Bad method");
2890  
2891          ListIterator<SIPHeader> list = request.getHeaders(SupportedHeader.NAME);
2892          if (list == null || !optionPresent(list, "100rel")) {
2893              list = request.getHeaders(RequireHeader.NAME);
2894              if (list == null || !optionPresent(list, "100rel")) {
2895                  throw new SipException("No Supported/Require 100rel header in the request");
2896              }
2897          }
2898  
2899          SIPResponse response = request.createResponse(statusCode);
2900          /*
2901           * The provisional response to be sent reliably is constructed by the UAS core according
2902           * to the procedures of Section 8.2.6 of RFC 3261. In addition, it MUST contain a Require
2903           * header field containing the option tag 100rel, and MUST include an RSeq header field.
2904           * The value of the header field for the first reliable provisional response in a
2905           * transaction MUST be between 1 and 2**31 - 1. It is RECOMMENDED that it be chosen
2906           * uniformly in this range. The RSeq numbering space is within a single transaction. This
2907           * means that provisional responses for different requests MAY use the same values for the
2908           * RSeq number.
2909           */
2910          Require require = new Require();
2911          try {
2912              require.setOptionTag("100rel");
2913          } catch (Exception ex) {
2914              InternalErrorHandler.handleException(ex);
2915          }
2916          response.addHeader(require);
2917          RSeq rseq = new RSeq();
2918          /*
2919           * set an arbitrary sequence number. This is actually set when the response is sent out
2920           */
2921          rseq.setSeqNumber(1L);
2922          /*
2923           * Copy the record route headers from the request to the response ( Issue 160 ). Note that
2924           * other 1xx headers do not get their Record Route headers copied over but reliable
2925           * provisional responses do. See RFC 3262 Table 2.
2926           */
2927          RecordRouteList rrl = request.getRecordRouteHeaders();
2928          if (rrl != null) {
2929              RecordRouteList rrlclone = (RecordRouteList) rrl.clone();
2930              response.setHeader(rrlclone);
2931          }
2932  
2933          return response;
2934      }
2935  
2936      /**
2937       * Do the processing necessary for the PRACK
2938       *
2939       * @param prackRequest
2940       * @return true if this is the first time the tx has seen the prack ( and hence needs to be
2941       *         passed up to the TU)
2942       */
handlePrack(SIPRequest prackRequest)2943      public boolean handlePrack(SIPRequest prackRequest) {
2944          /*
2945           * The RAck header is sent in a PRACK request to support reliability of provisional
2946           * responses. It contains two numbers and a method tag. The first number is the value from
2947           * the RSeq header in the provisional response that is being acknowledged. The next
2948           * number, and the method, are copied from the CSeq in the response that is being
2949           * acknowledged. The method name in the RAck header is case sensitive.
2950           */
2951          if (!this.isServer()) {
2952              if (sipStack.isLoggingEnabled())
2953                  sipStack.getStackLogger().logDebug("Dropping Prack -- not a server Dialog");
2954              return false;
2955          }
2956          SIPServerTransaction sipServerTransaction = (SIPServerTransaction) this
2957                  .getFirstTransaction();
2958          SIPResponse sipResponse = sipServerTransaction.getReliableProvisionalResponse();
2959  
2960          if (sipResponse == null) {
2961              if (sipStack.isLoggingEnabled())
2962                  sipStack.getStackLogger()
2963                          .logDebug("Dropping Prack -- ReliableResponse not found");
2964              return false;
2965          }
2966  
2967          RAck rack = (RAck) prackRequest.getHeader(RAckHeader.NAME);
2968  
2969          if (rack == null) {
2970              if (sipStack.isLoggingEnabled())
2971                  sipStack.getStackLogger().logDebug("Dropping Prack -- rack header not found");
2972              return false;
2973          }
2974          CSeq cseq = (CSeq) sipResponse.getCSeq();
2975  
2976          if (!rack.getMethod().equals(cseq.getMethod())) {
2977              if (sipStack.isLoggingEnabled())
2978                  sipStack.getStackLogger().logDebug(
2979                          "Dropping Prack -- CSeq Header does not match PRACK");
2980              return false;
2981          }
2982  
2983          if (rack.getCSeqNumberLong() != cseq.getSeqNumber()) {
2984              if (sipStack.isLoggingEnabled())
2985                  sipStack.getStackLogger().logDebug(
2986                          "Dropping Prack -- CSeq Header does not match PRACK");
2987              return false;
2988          }
2989  
2990          RSeq rseq = (RSeq) sipResponse.getHeader(RSeqHeader.NAME);
2991  
2992          if (rack.getRSequenceNumber() != rseq.getSeqNumber()) {
2993              if (sipStack.isLoggingEnabled())
2994                  sipStack.getStackLogger().logDebug(
2995                          "Dropping Prack -- RSeq Header does not match PRACK");
2996              return false;
2997          }
2998  
2999          return sipServerTransaction.prackRecieved();
3000      }
3001  
3002      /*
3003       * (non-Javadoc)
3004       *
3005       * @see javax.sip.Dialog#sendReliableProvisionalResponse(javax.sip.message.Response)
3006       */
sendReliableProvisionalResponse(Response relResponse)3007      public void sendReliableProvisionalResponse(Response relResponse) throws SipException {
3008          if (!this.isServer()) {
3009              throw new SipException("Not a Server Dialog");
3010          }
3011  
3012          SIPResponse sipResponse = (SIPResponse) relResponse;
3013  
3014          if (relResponse.getStatusCode() == 100)
3015              throw new SipException("Cannot send 100 as a reliable provisional response");
3016  
3017          if (relResponse.getStatusCode() / 100 > 2)
3018              throw new SipException(
3019                      "Response code is not a 1xx response - should be in the range 101 to 199 ");
3020  
3021          /*
3022           * Do a little checking on the outgoing response.
3023           */
3024          if (sipResponse.getToTag() == null) {
3025              throw new SipException(
3026                      "Badly formatted response -- To tag mandatory for Reliable Provisional Response");
3027          }
3028          ListIterator requireList = (ListIterator) relResponse.getHeaders(RequireHeader.NAME);
3029          boolean found = false;
3030  
3031          if (requireList != null) {
3032  
3033              while (requireList.hasNext() && !found) {
3034                  RequireHeader rh = (RequireHeader) requireList.next();
3035                  if (rh.getOptionTag().equalsIgnoreCase("100rel")) {
3036                      found = true;
3037                  }
3038              }
3039          }
3040  
3041          if (!found) {
3042              Require require = new Require("100rel");
3043              relResponse.addHeader(require);
3044              if (sipStack.isLoggingEnabled()) {
3045                  sipStack.getStackLogger().logDebug(
3046                          "Require header with optionTag 100rel is needed -- adding one");
3047              }
3048  
3049          }
3050  
3051          SIPServerTransaction serverTransaction = (SIPServerTransaction) this
3052                  .getFirstTransaction();
3053          /*
3054           * put into the dialog table before sending the response so as to avoid race condition
3055           * with PRACK
3056           */
3057          this.setLastResponse(serverTransaction, sipResponse);
3058  
3059          this.setDialogId(sipResponse.getDialogId(true));
3060  
3061          serverTransaction.sendReliableProvisionalResponse(relResponse);
3062  
3063          this.startRetransmitTimer(serverTransaction, relResponse);
3064  
3065      }
3066  
3067      /*
3068       * (non-Javadoc)
3069       *
3070       * @see javax.sip.Dialog#terminateOnBye(boolean)
3071       */
terminateOnBye(boolean terminateFlag)3072      public void terminateOnBye(boolean terminateFlag) throws SipException {
3073  
3074          this.terminateOnBye = terminateFlag;
3075      }
3076  
3077      /**
3078       * Set the "assigned" flag to true. We do this when inserting the dialog into the dialog table
3079       * of the stack.
3080       *
3081       */
setAssigned()3082      public void setAssigned() {
3083          this.isAssigned = true;
3084      }
3085  
3086      /**
3087       * Return true if the dialog has already been mapped to a transaction.
3088       *
3089       */
3090  
isAssigned()3091      public boolean isAssigned() {
3092          return this.isAssigned;
3093      }
3094  
3095      /**
3096       * Get the contact header that the owner of this dialog assigned. Subsequent Requests are
3097       * considered to belong to the dialog if the dialog identifier matches and the contact header
3098       * matches the ip address and port on which the request is received.
3099       *
3100       * @return contact header belonging to the dialog.
3101       */
getMyContactHeader()3102      public Contact getMyContactHeader() {
3103      	return contactHeader;
3104      }
3105  
3106      /**
3107       * Do the necessary processing to handle an ACK directed at this Dialog.
3108       *
3109       * @param ackTransaction -- the ACK transaction that was directed at this dialog.
3110       * @return -- true if the ACK was successfully consumed by the Dialog and resulted in the
3111       *         dialog state being changed.
3112       */
handleAck(SIPServerTransaction ackTransaction)3113      public boolean handleAck(SIPServerTransaction ackTransaction) {
3114          SIPRequest sipRequest = ackTransaction.getOriginalRequest();
3115  
3116          if (isAckSeen() && getRemoteSeqNumber() == sipRequest.getCSeq().getSeqNumber()) {
3117  
3118              if (sipStack.isLoggingEnabled()) {
3119                  sipStack.getStackLogger().logDebug(
3120                          "ACK already seen by dialog -- dropping Ack" + " retransmission");
3121              }
3122              acquireTimerTaskSem();
3123              try {
3124              	if (this.timerTask != null) {
3125  	                this.timerTask.cancel();
3126  	                this.timerTask = null;
3127              	}
3128              } finally {
3129          		releaseTimerTaskSem();
3130          	}
3131              return false;
3132          } else if (this.getState() == DialogState.TERMINATED) {
3133              if (sipStack.isLoggingEnabled())
3134                  sipStack.getStackLogger().logDebug("Dialog is terminated -- dropping ACK");
3135              return false;
3136  
3137          } else {
3138  
3139              /*
3140               * This could be a re-invite processing. check to see if the ack matches with the last
3141               * transaction. s
3142               */
3143  
3144              SIPServerTransaction tr = getInviteTransaction();
3145  
3146              SIPResponse sipResponse = (tr != null ? tr.getLastResponse() : null);
3147  
3148              // Idiot check for sending ACK from the wrong side!
3149              if (tr != null
3150                      && sipResponse != null
3151                      && sipResponse.getStatusCode() / 100 == 2
3152                      && sipResponse.getCSeq().getMethod().equals(Request.INVITE)
3153                      && sipResponse.getCSeq().getSeqNumber() == sipRequest.getCSeq()
3154                              .getSeqNumber()) {
3155  
3156                  ackTransaction.setDialog(this, sipResponse.getDialogId(false));
3157                  /*
3158                   * record that we already saw an ACK for this dialog.
3159                   */
3160  
3161                  ackReceived(sipRequest);
3162                  if (sipStack.isLoggingEnabled())
3163                  	sipStack.getStackLogger().logDebug("ACK for 2XX response --- sending to TU ");
3164                  return true;
3165  
3166              } else {
3167                  /*
3168                   * This happens when the ACK is re-transmitted and arrives too late to be
3169                   * processed.
3170                   */
3171  
3172                  if (sipStack.isLoggingEnabled())
3173                      sipStack.getStackLogger().logDebug(
3174                              " INVITE transaction not found  -- Discarding ACK");
3175                  return false;
3176              }
3177          }
3178      }
3179  
setEarlyDialogId(String earlyDialogId)3180      void setEarlyDialogId(String earlyDialogId) {
3181          this.earlyDialogId = earlyDialogId;
3182      }
3183  
getEarlyDialogId()3184      String getEarlyDialogId() {
3185          return earlyDialogId;
3186      }
3187  
3188      /**
3189       * Release the semaphore for ACK processing so the next re-INVITE may proceed.
3190       */
releaseAckSem()3191      void releaseAckSem() {
3192          if (this.isBackToBackUserAgent) {
3193              if (sipStack.isLoggingEnabled()) {
3194                  sipStack.getStackLogger().logDebug("releaseAckSem]" + this);
3195              }
3196              this.ackSem.release();
3197          }
3198  
3199      }
3200  
takeAckSem()3201      boolean takeAckSem() {
3202          if (sipStack.isLoggingEnabled()) {
3203              sipStack.getStackLogger().logDebug("[takeAckSem " + this);
3204          }
3205          try {
3206              if (!this.ackSem.tryAcquire(2, TimeUnit.SECONDS)) {
3207                  if (sipStack.isLoggingEnabled()) {
3208                      sipStack.getStackLogger().logError("Cannot aquire ACK semaphore");
3209                  }
3210  
3211                  if ( sipStack.isLoggingEnabled() ) {
3212                      sipStack.getStackLogger().logDebug("Semaphore previously acquired at " + this.stackTrace);
3213                      sipStack.getStackLogger().logStackTrace();
3214  
3215                  }
3216                  return false;
3217              }
3218  
3219              if ( sipStack.isLoggingEnabled() ) {
3220  
3221                  this.recordStackTrace();
3222              }
3223  
3224          } catch (InterruptedException ex) {
3225              sipStack.getStackLogger().logError("Cannot aquire ACK semaphore");
3226              return false;
3227  
3228          }
3229          return true;
3230  
3231      }
3232  
3233      /**
3234       * @param lastAckReceived the lastAckReceived to set
3235       */
setLastAckReceived(SIPRequest lastAckReceived)3236      private void setLastAckReceived(SIPRequest lastAckReceived) {
3237          this.lastAckReceived = lastAckReceived;
3238      }
3239  
3240      /**
3241       * @return the lastAckReceived
3242       */
getLastAckReceived()3243      protected SIPRequest getLastAckReceived() {
3244          return lastAckReceived;
3245      }
3246  
3247      /**
3248       * @param lastAckSent the lastAckSent to set
3249       */
setLastAckSent(SIPRequest lastAckSent)3250      private void setLastAckSent(SIPRequest lastAckSent) {
3251          this.lastAckSent = lastAckSent;
3252      }
3253  
3254      /**
3255       * @return true if an ack was ever sent for this Dialog
3256       */
isAtleastOneAckSent()3257      public boolean isAtleastOneAckSent() {
3258          return this.isAcknowledged;
3259      }
3260  
3261  
3262  
isBackToBackUserAgent()3263      public boolean isBackToBackUserAgent() {
3264          return this.isBackToBackUserAgent;
3265      }
3266  
doDeferredDeleteIfNoAckSent(long seqno)3267      public synchronized void doDeferredDeleteIfNoAckSent(long seqno) {
3268  		if (sipStack.getTimer() == null) {
3269  			this.setState(TERMINATED_STATE);
3270  		} else if(dialogDeleteIfNoAckSentTask == null){
3271  			// Delete the transaction after the max ack timeout.
3272  			dialogDeleteIfNoAckSentTask = new DialogDeleteIfNoAckSentTask(seqno);
3273  			sipStack.getTimer().schedule(
3274  					dialogDeleteIfNoAckSentTask,
3275  					SIPTransaction.TIMER_J
3276  							* SIPTransactionStack.BASE_TIMER_INTERVAL);
3277  		}
3278  	}
3279  
3280      /*
3281       * (non-Javadoc)
3282       * @see gov.nist.javax.sip.DialogExt#setBackToBackUserAgent(boolean)
3283       */
setBackToBackUserAgent()3284      public void setBackToBackUserAgent() {
3285          this.isBackToBackUserAgent = true;
3286      }
3287  
3288  	/**
3289  	 * @return the eventHeader
3290  	 */
getEventHeader()3291  	EventHeader getEventHeader() {
3292  		return eventHeader;
3293  	}
3294  
3295  	/**
3296  	 * @param eventHeader the eventHeader to set
3297  	 */
setEventHeader(EventHeader eventHeader)3298  	void setEventHeader(EventHeader eventHeader) {
3299  		this.eventHeader = eventHeader;
3300  	}
3301  
3302  	/**
3303  	 * @param serverTransactionFlag the serverTransactionFlag to set
3304  	 */
setServerTransactionFlag(boolean serverTransactionFlag)3305  	void setServerTransactionFlag(boolean serverTransactionFlag) {
3306  		this.serverTransactionFlag = serverTransactionFlag;
3307  	}
3308  
3309  	/**
3310  	 * @param reInviteFlag the reinviteFlag to set
3311  	 */
setReInviteFlag(boolean reInviteFlag)3312  	void setReInviteFlag(boolean reInviteFlag) {
3313  		this.reInviteFlag = reInviteFlag;
3314  	}
3315  
3316  
isSequnceNumberValidation()3317  	public boolean isSequnceNumberValidation() {
3318  	    return this.sequenceNumberValidation;
3319  	}
3320  
disableSequenceNumberValidation()3321      public void disableSequenceNumberValidation() {
3322          this.sequenceNumberValidation = false;
3323      }
3324  
3325  
acquireTimerTaskSem()3326      public void acquireTimerTaskSem() {
3327      	boolean acquired = false;
3328          try {
3329              acquired = this.timerTaskLock.tryAcquire(10, TimeUnit.SECONDS);
3330          } catch ( InterruptedException ex) {
3331              acquired = false;
3332          }
3333          if(!acquired) {
3334          	throw new IllegalStateException("Impossible to acquire the dialog timer task lock");
3335          }
3336      }
3337  
releaseTimerTaskSem()3338      public void releaseTimerTaskSem() {
3339          this.timerTaskLock.release();
3340      }
3341  
3342  
3343  }
3344