• 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/ITL Advanced Networking Technologies Division (ANTD).      *
28  ******************************************************************************/
29 package gov.nist.javax.sip;
30 
31 import gov.nist.core.InternalErrorHandler;
32 import gov.nist.javax.sip.DialogTimeoutEvent.Reason;
33 import gov.nist.javax.sip.address.RouterExt;
34 import gov.nist.javax.sip.header.CallID;
35 import gov.nist.javax.sip.header.Via;
36 import gov.nist.javax.sip.message.SIPMessage;
37 import gov.nist.javax.sip.message.SIPRequest;
38 import gov.nist.javax.sip.message.SIPResponse;
39 import gov.nist.javax.sip.stack.HopImpl;
40 import gov.nist.javax.sip.stack.MessageChannel;
41 import gov.nist.javax.sip.stack.SIPClientTransaction;
42 import gov.nist.javax.sip.stack.SIPDialog;
43 import gov.nist.javax.sip.stack.SIPDialogErrorEvent;
44 import gov.nist.javax.sip.stack.SIPDialogEventListener;
45 import gov.nist.javax.sip.stack.SIPServerTransaction;
46 import gov.nist.javax.sip.stack.SIPTransaction;
47 import gov.nist.javax.sip.stack.SIPTransactionErrorEvent;
48 import gov.nist.javax.sip.stack.SIPTransactionEventListener;
49 
50 import java.io.IOException;
51 import java.text.ParseException;
52 import java.util.EventObject;
53 import java.util.Iterator;
54 import java.util.TooManyListenersException;
55 import java.util.concurrent.ConcurrentHashMap;
56 
57 import javax.sip.ClientTransaction;
58 import javax.sip.Dialog;
59 import javax.sip.DialogState;
60 import javax.sip.InvalidArgumentException;
61 import javax.sip.ListeningPoint;
62 import javax.sip.ObjectInUseException;
63 import javax.sip.RequestEvent;
64 import javax.sip.ResponseEvent;
65 import javax.sip.ServerTransaction;
66 import javax.sip.SipException;
67 import javax.sip.SipListener;
68 import javax.sip.SipStack;
69 import javax.sip.Timeout;
70 import javax.sip.TimeoutEvent;
71 import javax.sip.Transaction;
72 import javax.sip.TransactionAlreadyExistsException;
73 import javax.sip.TransactionState;
74 import javax.sip.TransactionUnavailableException;
75 import javax.sip.address.Hop;
76 import javax.sip.header.CallIdHeader;
77 import javax.sip.message.Request;
78 import javax.sip.message.Response;
79 
80 /*
81  * Contributions (bug fixes) made by: Daniel J. Martinez Manzano, Hagai Sela.
82  * Bug reports by Shanti Kadiyala, Rhys Ulerich,Victor Hugo
83  */
84 /**
85  * Implementation of the JAIN-SIP provider interface.
86  *
87  * @version 1.2 $Revision: 1.82 $ $Date: 2009/11/24 17:16:59 $
88  *
89  * @author M. Ranganathan <br/>
90  *
91  *
92  */
93 
94 public class SipProviderImpl implements javax.sip.SipProvider, gov.nist.javax.sip.SipProviderExt,
95         SIPTransactionEventListener, SIPDialogEventListener {
96 
97     private SipListener sipListener;
98 
99     protected SipStackImpl sipStack;
100 
101     /*
102      * A set of listening points associated with the provider At most one LP per
103      * transport
104      */
105     private ConcurrentHashMap listeningPoints;
106 
107     private EventScanner eventScanner;
108 
109     private String address;
110 
111     private int port;
112 
113     private boolean automaticDialogSupportEnabled ;
114     /**
115      * A string containing the 0.0.0.0 IPv4 ANY address.
116      */
117     private String IN_ADDR_ANY = "0.0.0.0";
118 
119     /**
120      * A string containing the ::0 IPv6 ANY address.
121      */
122     private String IN6_ADDR_ANY = "::0";
123 
124     private boolean dialogErrorsAutomaticallyHandled = true;
125 
SipProviderImpl()126     private SipProviderImpl() {
127 
128     }
129 
130     /**
131      * Stop processing messages for this provider. Post an empty message to our
132      * message processing queue that signals us to quit.
133      */
stop()134     protected void stop() {
135         // Put an empty event in the queue and post ourselves a message.
136         if (sipStack.isLoggingEnabled())
137             sipStack.getStackLogger().logDebug("Exiting provider");
138         for (Iterator it = listeningPoints.values().iterator(); it.hasNext();) {
139             ListeningPointImpl listeningPoint = (ListeningPointImpl) it.next();
140             listeningPoint.removeSipProvider();
141         }
142         this.eventScanner.stop();
143 
144     }
145 
146     /*
147      * (non-Javadoc)
148      *
149      * @see javax.sip.SipProvider#getListeningPoint(java.lang.String)
150      */
getListeningPoint(String transport)151     public ListeningPoint getListeningPoint(String transport) {
152         if (transport == null)
153             throw new NullPointerException("Null transport param");
154         return (ListeningPoint) this.listeningPoints.get(transport
155                 .toUpperCase());
156     }
157 
158     /**
159      * Handle the SIP event - because we have only one listener and we are
160      * already in the context of a separate thread, we dont need to enque the
161      * event and signal another thread.
162      *
163      * @param sipEvent
164      *            is the event to process.
165      *
166      */
167 
handleEvent(EventObject sipEvent, SIPTransaction transaction)168     public void handleEvent(EventObject sipEvent, SIPTransaction transaction) {
169         if (sipStack.isLoggingEnabled()) {
170             sipStack.getStackLogger().logDebug(
171                     "handleEvent " + sipEvent + "currentTransaction = "
172                             + transaction + "this.sipListener = "
173                             + this.getSipListener() + "sipEvent.source = "
174                             + sipEvent.getSource());
175             if (sipEvent instanceof RequestEvent) {
176                 Dialog dialog = ((RequestEvent) sipEvent).getDialog();
177                 if ( sipStack.isLoggingEnabled())  sipStack.getStackLogger().logDebug("Dialog = " + dialog);
178             } else if (sipEvent instanceof ResponseEvent) {
179                 Dialog dialog = ((ResponseEvent) sipEvent).getDialog();
180                 if (sipStack.isLoggingEnabled() ) sipStack.getStackLogger().logDebug("Dialog = " + dialog);
181             }
182             sipStack.getStackLogger().logStackTrace();
183         }
184 
185         EventWrapper eventWrapper = new EventWrapper(sipEvent, transaction);
186 
187         if (!sipStack.reEntrantListener) {
188             // Run the event in the context of a single thread.
189             this.eventScanner.addEvent(eventWrapper);
190         } else {
191             // just call the delivery method
192             this.eventScanner.deliverEvent(eventWrapper);
193         }
194     }
195 
196     /** Creates a new instance of SipProviderImpl */
SipProviderImpl(SipStackImpl sipStack)197     protected SipProviderImpl(SipStackImpl sipStack) {
198         this.eventScanner = sipStack.getEventScanner(); // for quick access.
199         this.sipStack = sipStack;
200         this.eventScanner.incrementRefcount();
201         this.listeningPoints = new ConcurrentHashMap<String,ListeningPointImpl>();
202         this.automaticDialogSupportEnabled = this.sipStack
203                 .isAutomaticDialogSupportEnabled();
204         this.dialogErrorsAutomaticallyHandled = this.sipStack.isAutomaticDialogErrorHandlingEnabled();
205     }
206 
207     /*
208      * (non-Javadoc)
209      *
210      * @see java.lang.Object#clone()
211      */
clone()212     protected Object clone() throws java.lang.CloneNotSupportedException {
213         throw new java.lang.CloneNotSupportedException();
214     }
215 
216 
217     /*
218      * (non-Javadoc)
219      *
220      * @see javax.sip.SipProvider#addSipListener(javax.sip.SipListener)
221      */
addSipListener(SipListener sipListener)222     public void addSipListener(SipListener sipListener)
223             throws TooManyListenersException {
224 
225         if (sipStack.sipListener == null) {
226             sipStack.sipListener = sipListener;
227         } else if (sipStack.sipListener != sipListener) {
228             throw new TooManyListenersException(
229                     "Stack already has a listener. Only one listener per stack allowed");
230         }
231 
232         if (sipStack.isLoggingEnabled())
233             sipStack.getStackLogger().logDebug("add SipListener " + sipListener);
234         this.sipListener = sipListener;
235 
236     }
237 
238     /*
239      * This method is deprecated (non-Javadoc)
240      *
241      * @see javax.sip.SipProvider#getListeningPoint()
242      */
243 
getListeningPoint()244     public ListeningPoint getListeningPoint() {
245         if (this.listeningPoints.size() > 0)
246             return (ListeningPoint) this.listeningPoints.values().iterator()
247                     .next();
248         else
249             return null;
250     }
251 
252     /*
253      * (non-Javadoc)
254      *
255      * @see javax.sip.SipProvider#getNewCallId()
256      */
getNewCallId()257     public CallIdHeader getNewCallId() {
258         String callId = Utils.getInstance().generateCallIdentifier(this.getListeningPoint()
259                 .getIPAddress());
260         CallID callid = new CallID();
261         try {
262             callid.setCallId(callId);
263         } catch (java.text.ParseException ex) {
264         }
265         return callid;
266 
267     }
268 
269     /*
270      * (non-Javadoc)
271      *
272      * @see javax.sip.SipProvider#getNewClientTransaction(javax.sip.message.Request)
273      */
getNewClientTransaction(Request request)274     public ClientTransaction getNewClientTransaction(Request request)
275             throws TransactionUnavailableException {
276         if (request == null)
277             throw new NullPointerException("null request");
278         if (!sipStack.isAlive())
279             throw new TransactionUnavailableException("Stack is stopped");
280 
281         SIPRequest sipRequest = (SIPRequest) request;
282         if (sipRequest.getTransaction() != null)
283             throw new TransactionUnavailableException(
284                     "Transaction already assigned to request");
285         if ( sipRequest.getMethod().equals(Request.ACK)) {
286             throw new TransactionUnavailableException ("Cannot create client transaction for  " + Request.ACK);
287         }
288         // Be kind and assign a via header for this provider if the user is
289         // sloppy
290         if (sipRequest.getTopmostVia() == null) {
291             ListeningPointImpl lp = (ListeningPointImpl) this
292                     .getListeningPoint("udp");
293             Via via = lp.getViaHeader();
294             request.setHeader(via);
295         }
296         // Give the request a quick check to see if all headers are assigned.
297         try {
298             sipRequest.checkHeaders();
299         } catch (ParseException ex) {
300             throw new TransactionUnavailableException(ex.getMessage(), ex);
301         }
302 
303         /*
304          * User decided to give us his own via header branch. Lets see if it
305          * results in a clash. If so reject the request.
306          */
307         if (sipRequest.getTopmostVia().getBranch() != null
308                 && sipRequest.getTopmostVia().getBranch().startsWith(
309                         SIPConstants.BRANCH_MAGIC_COOKIE)
310                 && sipStack.findTransaction((SIPRequest) request, false) != null) {
311             throw new TransactionUnavailableException(
312                     "Transaction already exists!");
313         }
314 
315 
316 
317 
318         if (request.getMethod().equalsIgnoreCase(Request.CANCEL)) {
319             SIPClientTransaction ct = (SIPClientTransaction) sipStack
320                     .findCancelTransaction((SIPRequest) request, false);
321             if (ct != null) {
322                 ClientTransaction retval = sipStack.createClientTransaction(
323                         (SIPRequest) request, ct.getMessageChannel());
324 
325                 ((SIPTransaction) retval).addEventListener(this);
326                 sipStack.addTransaction((SIPClientTransaction) retval);
327                 if (ct.getDialog() != null) {
328                     ((SIPClientTransaction) retval).setDialog((SIPDialog) ct
329                             .getDialog(), sipRequest.getDialogId(false));
330 
331                 }
332                 return retval;
333             }
334 
335         }
336         if (sipStack.isLoggingEnabled())
337             sipStack.getStackLogger().logDebug(
338                     "could not find existing transaction for "
339                             + ((SIPRequest) request).getFirstLine()
340                             + " creating a new one ");
341 
342         // Could not find a dialog or the route is not set in dialog.
343 
344         Hop hop = null;
345         try {
346             hop = sipStack.getNextHop((SIPRequest) request);
347             if (hop == null)
348                 throw new TransactionUnavailableException(
349                         "Cannot resolve next hop -- transaction unavailable");
350         } catch (SipException ex) {
351             throw new TransactionUnavailableException(
352                     "Cannot resolve next hop -- transaction unavailable", ex);
353         }
354         String transport = hop.getTransport();
355         ListeningPointImpl listeningPoint = (ListeningPointImpl) this
356                 .getListeningPoint(transport);
357 
358         String dialogId = sipRequest.getDialogId(false);
359         SIPDialog dialog = sipStack.getDialog(dialogId);
360         if (dialog != null && dialog.getState() == DialogState.TERMINATED) {
361 
362             // throw new TransactionUnavailableException
363             // ("Found a terminated dialog -- possible re-use of old tag
364             // parameters");
365             sipStack.removeDialog(dialog);
366 
367         }
368 
369         // An out of dialog route was found. Assign this to the
370         // client transaction.
371 
372         try {
373             // Set the brannch id before you ask for a tx.
374             // If the user has set his own branch Id and the
375             // branch id starts with a valid prefix, then take it.
376             // otherwise, generate one. If branch ID checking has
377             // been requested, set the branch ID.
378             String branchId = null;
379             if (sipRequest.getTopmostVia().getBranch() == null
380                     || !sipRequest.getTopmostVia().getBranch().startsWith(
381                             SIPConstants.BRANCH_MAGIC_COOKIE)
382                             || sipStack.checkBranchId() ) {
383                 branchId = Utils.getInstance().generateBranchId();
384 
385                 sipRequest.getTopmostVia().setBranch(branchId);
386             }
387             Via topmostVia = sipRequest.getTopmostVia();
388 
389             //set port and transport if user hasn't already done this.
390             if(topmostVia.getTransport() == null)
391                 topmostVia.setTransport(transport);
392 
393             if(topmostVia.getPort() == -1)
394                 topmostVia.setPort(listeningPoint.getPort());
395             branchId = sipRequest.getTopmostVia().getBranch();
396 
397             SIPClientTransaction ct = (SIPClientTransaction) sipStack
398                     .createMessageChannel(sipRequest, listeningPoint
399                             .getMessageProcessor(), hop);
400             if (ct == null)
401                 throw new TransactionUnavailableException("Cound not create tx");
402             ct.setNextHop(hop);
403             ct.setOriginalRequest(sipRequest);
404             ct.setBranch(branchId);
405             // if the stack supports dialogs then
406             if (sipStack.isDialogCreated(request.getMethod())) {
407                 // create a new dialog to contain this transaction
408                 // provided this is necessary.
409                 // This could be a re-invite
410                 // in which case the dialog is re-used.
411                 // (but noticed by Brad Templeton)
412                 if (dialog != null)
413                     ct.setDialog(dialog, sipRequest.getDialogId(false));
414                 else if (this.isAutomaticDialogSupportEnabled()) {
415                     SIPDialog sipDialog = sipStack.createDialog(ct);
416                     ct.setDialog(sipDialog, sipRequest.getDialogId(false));
417                 }
418             } else {
419                 if (dialog != null) {
420                     ct.setDialog(dialog, sipRequest.getDialogId(false));
421                 }
422 
423             }
424 
425             // The provider is the event listener for all transactions.
426             ct.addEventListener(this);
427             return (ClientTransaction) ct;
428         } catch (IOException ex) {
429 
430             throw new TransactionUnavailableException(
431                     "Could not resolve next hop or listening point unavailable! ",
432                     ex);
433 
434         } catch (java.text.ParseException ex) {
435             InternalErrorHandler.handleException(ex);
436             throw new TransactionUnavailableException(
437                     "Unexpected Exception FIXME! ", ex);
438         } catch (InvalidArgumentException ex) {
439             InternalErrorHandler.handleException(ex);
440             throw new TransactionUnavailableException(
441                     "Unexpected Exception FIXME! ", ex);
442         }
443 
444     }
445 
446     /*
447      * (non-Javadoc)
448      *
449      * @see javax.sip.SipProvider#getNewServerTransaction(javax.sip.message.Request)
450      */
getNewServerTransaction(Request request)451     public ServerTransaction getNewServerTransaction(Request request)
452             throws TransactionAlreadyExistsException,
453             TransactionUnavailableException {
454 
455         if (!sipStack.isAlive())
456             throw new TransactionUnavailableException("Stack is stopped");
457         SIPServerTransaction transaction = null;
458         SIPRequest sipRequest = (SIPRequest) request;
459         try {
460             sipRequest.checkHeaders();
461         } catch (ParseException ex) {
462             throw new TransactionUnavailableException(ex.getMessage(), ex);
463         }
464 
465         if ( request.getMethod().equals(Request.ACK)) {
466             if ( sipStack.isLoggingEnabled())
467                 sipStack.getStackLogger().logError("Creating server transaction for ACK -- makes no sense!");
468             throw new TransactionUnavailableException("Cannot create Server transaction for ACK ");
469         }
470         /*
471          * Got a notify.
472          */
473         if (sipRequest.getMethod().equals(Request.NOTIFY)
474                 && sipRequest.getFromTag() != null
475                 && sipRequest.getToTag() == null) {
476 
477             SIPClientTransaction ct = sipStack.findSubscribeTransaction(
478                     sipRequest, (ListeningPointImpl) this.getListeningPoint());
479             /* Issue 104 */
480             if (ct == null && ! sipStack.deliverUnsolicitedNotify) {
481                 throw new TransactionUnavailableException(
482                         "Cannot find matching Subscription (and gov.nist.javax.sip.DELIVER_UNSOLICITED_NOTIFY not set)");
483             }
484         }
485         if ( !sipStack.acquireSem()) {
486             throw new TransactionUnavailableException(
487             "Transaction not available -- could not acquire stack lock");
488         }
489         try {
490             if (sipStack.isDialogCreated(sipRequest.getMethod())) {
491                 if (sipStack.findTransaction((SIPRequest) request, true) != null)
492                     throw new TransactionAlreadyExistsException(
493                     "server transaction already exists!");
494 
495                 transaction = (SIPServerTransaction) ((SIPRequest) request)
496                 .getTransaction();
497                 if (transaction == null)
498                     throw new TransactionUnavailableException(
499                     "Transaction not available");
500                 if (transaction.getOriginalRequest() == null)
501                     transaction.setOriginalRequest(sipRequest);
502                 try {
503                     sipStack.addTransaction(transaction);
504                 } catch (IOException ex) {
505                     throw new TransactionUnavailableException(
506                     "Error sending provisional response");
507                 }
508                 // So I can handle timeouts.
509                 transaction.addEventListener(this);
510                 if (isAutomaticDialogSupportEnabled()) {
511                     // If automatic dialog support is enabled then
512                     // this tx gets his own dialog.
513                     String dialogId = sipRequest.getDialogId(true);
514                     SIPDialog dialog = sipStack.getDialog(dialogId);
515                     if (dialog == null) {
516                         dialog = sipStack.createDialog(transaction);
517 
518                     }
519                     transaction.setDialog(dialog, sipRequest.getDialogId(true));
520                     if (sipRequest.getMethod().equals(Request.INVITE) && this.isDialogErrorsAutomaticallyHandled()) {
521                         sipStack.putInMergeTable(transaction, sipRequest);
522                     }
523                     dialog.addRoute(sipRequest);
524                     if (dialog.getRemoteTag() != null
525                             && dialog.getLocalTag() != null) {
526                         this.sipStack.putDialog(dialog);
527                     }
528                 }
529 
530             } else {
531                 if (isAutomaticDialogSupportEnabled()) {
532                     /*
533                      * Under automatic dialog support, dialog is tied into a transaction. You cannot
534                      * create a server tx except for dialog creating transactions. After that, all
535                      * subsequent transactions are created for you by the stack.
536                      */
537                     transaction = (SIPServerTransaction) sipStack.findTransaction(
538                             (SIPRequest) request, true);
539                     if (transaction != null)
540                         throw new TransactionAlreadyExistsException(
541                         "Transaction exists! ");
542                     transaction = (SIPServerTransaction) ((SIPRequest) request)
543                     .getTransaction();
544                     if (transaction == null)
545                         throw new TransactionUnavailableException(
546                         "Transaction not available!");
547                     if (transaction.getOriginalRequest() == null)
548                         transaction.setOriginalRequest(sipRequest);
549                     // Map the transaction.
550                     try {
551                         sipStack.addTransaction(transaction);
552                     } catch (IOException ex) {
553                         throw new TransactionUnavailableException(
554                         "Could not send back provisional response!");
555                     }
556 
557                     // If there is a dialog already assigned then just update the
558                     // dialog state.
559                     String dialogId = sipRequest.getDialogId(true);
560                     SIPDialog dialog = sipStack.getDialog(dialogId);
561                     if (dialog != null) {
562                         dialog.addTransaction(transaction);
563                         dialog.addRoute(sipRequest);
564                         transaction.setDialog(dialog, sipRequest.getDialogId(true));
565                     }
566 
567                 } else {
568                     transaction = (SIPServerTransaction) sipStack.findTransaction(
569                             (SIPRequest) request, true);
570                     if (transaction != null)
571                         throw new TransactionAlreadyExistsException(
572                         "Transaction exists! ");
573                     transaction = (SIPServerTransaction) ((SIPRequest) request)
574                     .getTransaction();
575                     if (transaction != null) {
576                         if (transaction.getOriginalRequest() == null)
577                             transaction.setOriginalRequest(sipRequest);
578                         // Map the transaction.
579                         sipStack.mapTransaction(transaction);
580 
581                         // If there is a dialog already assigned then just
582                         // assign the dialog to the transaction.
583                         String dialogId = sipRequest.getDialogId(true);
584                         SIPDialog dialog = sipStack.getDialog(dialogId);
585                         if (dialog != null) {
586                             dialog.addTransaction(transaction);
587                             dialog.addRoute(sipRequest);
588                             transaction.setDialog(dialog, sipRequest
589                                     .getDialogId(true));
590                         }
591 
592                         return transaction;
593                     } else {
594                         // tx does not exist so create the tx.
595 
596                         MessageChannel mc = (MessageChannel) sipRequest
597                         .getMessageChannel();
598                         transaction = sipStack.createServerTransaction(mc);
599                         if (transaction == null)
600                             throw new TransactionUnavailableException(
601                             "Transaction unavailable -- too many servrer transactions");
602 
603                         transaction.setOriginalRequest(sipRequest);
604                         sipStack.mapTransaction(transaction);
605 
606                         // If there is a dialog already assigned then just
607                         // assign the dialog to the transaction.
608                         String dialogId = sipRequest.getDialogId(true);
609                         SIPDialog dialog = sipStack.getDialog(dialogId);
610                         if (dialog != null) {
611                             dialog.addTransaction(transaction);
612                             dialog.addRoute(sipRequest);
613                             transaction.setDialog(dialog, sipRequest
614                                     .getDialogId(true));
615                         }
616 
617                         return transaction;
618                     }
619                 }
620 
621             }
622             return transaction;
623         } finally {
624             sipStack.releaseSem();
625         }
626 
627     }
628 
629     /*
630      * (non-Javadoc)
631      *
632      * @see javax.sip.SipProvider#getSipStack()
633      */
getSipStack()634     public SipStack getSipStack() {
635         return (SipStack) this.sipStack;
636     }
637 
638     /*
639      * (non-Javadoc)
640      *
641      * @see javax.sip.SipProvider#removeSipListener(javax.sip.SipListener)
642      */
removeSipListener(SipListener sipListener)643     public void removeSipListener(SipListener sipListener) {
644         if (sipListener == this.getSipListener()) {
645             this.sipListener = null;
646         }
647 
648         boolean found = false;
649 
650         for (Iterator<SipProviderImpl> it = sipStack.getSipProviders(); it.hasNext();) {
651             SipProviderImpl nextProvider = (SipProviderImpl) it.next();
652             if (nextProvider.getSipListener() != null)
653                 found = true;
654         }
655         if (!found) {
656             sipStack.sipListener = null;
657         }
658     }
659 
660     /*
661      * (non-Javadoc)
662      *
663      * @see javax.sip.SipProvider#sendRequest(javax.sip.message.Request)
664      */
sendRequest(Request request)665     public void sendRequest(Request request) throws SipException {
666         if (!sipStack.isAlive())
667             throw new SipException("Stack is stopped.");
668 
669         // mranga: added check to ensure we are not sending empty (keepalive)
670         // message.
671         if (((SIPRequest) request).getRequestLine() != null
672                 && request.getMethod().equals(Request.ACK)) {
673             Dialog dialog = sipStack.getDialog(((SIPRequest) request)
674                     .getDialogId(false));
675             if (dialog != null && dialog.getState() != null) {
676             	if (sipStack.isLoggingEnabled())
677             		sipStack.getStackLogger().logWarning(
678                         "Dialog exists -- you may want to use Dialog.sendAck() "
679                                 + dialog.getState());
680             }
681         }
682         Hop hop = sipStack.getRouter((SIPRequest) request).getNextHop(request);
683         if (hop == null)
684             throw new SipException("could not determine next hop!");
685         SIPRequest sipRequest = (SIPRequest) request;
686         // Check if we have a valid via.
687         // Null request is used to send default proxy keepalive messages.
688         if ((!sipRequest.isNullRequest()) && sipRequest.getTopmostVia() == null)
689             throw new SipException("Invalid SipRequest -- no via header!");
690 
691         try {
692             /*
693              * JvB: Via branch should already be OK, dont touch it here? Some
694              * apps forward statelessly, and then it's not set. So set only when
695              * not set already, dont overwrite CANCEL branch here..
696              */
697             if (!sipRequest.isNullRequest()) {
698                 Via via = sipRequest.getTopmostVia();
699                 String branch = via.getBranch();
700                 if (branch == null || branch.length() == 0) {
701                     via.setBranch(sipRequest.getTransactionId());
702                 }
703             }
704             MessageChannel messageChannel = null;
705             if (this.listeningPoints.containsKey(hop.getTransport()
706                     .toUpperCase()))
707                 messageChannel = sipStack.createRawMessageChannel(
708                         this.getListeningPoint(hop.getTransport()).getIPAddress(),
709                         this.getListeningPoint(hop.getTransport()).getPort(), hop);
710             if (messageChannel != null) {
711                 messageChannel.sendMessage((SIPMessage) sipRequest,hop);
712             } else {
713                 throw new SipException(
714                         "Could not create a message channel for "
715                                 + hop.toString());
716             }
717         } catch (IOException ex) {
718             if (sipStack.isLoggingEnabled()) {
719                 sipStack.getStackLogger().logException(ex);
720             }
721 
722             throw new SipException(
723                     "IO Exception occured while Sending Request", ex);
724 
725         } catch (ParseException ex1) {
726             InternalErrorHandler.handleException(ex1);
727         } finally {
728             if (sipStack.isLoggingEnabled())
729                 sipStack.getStackLogger().logDebug(
730                         "done sending " + request.getMethod() + " to hop "
731                                 + hop);
732         }
733     }
734 
735     /*
736      * (non-Javadoc)
737      *
738      * @see javax.sip.SipProvider#sendResponse(javax.sip.message.Response)
739      */
sendResponse(Response response)740     public void sendResponse(Response response) throws SipException {
741         if (!sipStack.isAlive())
742             throw new SipException("Stack is stopped");
743         SIPResponse sipResponse = (SIPResponse) response;
744         Via via = sipResponse.getTopmostVia();
745         if (via == null)
746             throw new SipException("No via header in response!");
747         SIPServerTransaction st = (SIPServerTransaction) sipStack.findTransaction((SIPMessage)response, true);
748         if ( st != null   && st.getState() != TransactionState.TERMINATED && this.isAutomaticDialogSupportEnabled()) {
749             throw new SipException("Transaction exists -- cannot send response statelessly");
750         }
751         String transport = via.getTransport();
752 
753         // check to see if Via has "received paramaeter". If so
754         // set the host to the via parameter. Else set it to the
755         // Via host.
756         String host = via.getReceived();
757 
758         if (host == null)
759             host = via.getHost();
760 
761         // Symmetric nat support
762         int port = via.getRPort();
763         if (port == -1) {
764             port = via.getPort();
765             if (port == -1) {
766                 if (transport.equalsIgnoreCase("TLS"))
767                     port = 5061;
768                 else
769                     port = 5060;
770             }
771         }
772 
773         // for correct management of IPv6 addresses.
774         if (host.indexOf(":") > 0)
775             if (host.indexOf("[") < 0)
776                 host = "[" + host + "]";
777 
778         Hop hop = sipStack.getAddressResolver().resolveAddress(
779                 new HopImpl(host, port, transport));
780 
781         try {
782             ListeningPointImpl listeningPoint = (ListeningPointImpl) this
783                     .getListeningPoint(transport);
784             if (listeningPoint == null)
785                 throw new SipException(
786                         "whoopsa daisy! no listening point found for transport "
787                                 + transport);
788             MessageChannel messageChannel = sipStack.createRawMessageChannel(
789                     this.getListeningPoint(hop.getTransport()).getIPAddress(),
790                     listeningPoint.port, hop);
791             messageChannel.sendMessage(sipResponse);
792         } catch (IOException ex) {
793             throw new SipException(ex.getMessage());
794         }
795     }
796 
797     /*
798      * (non-Javadoc)
799      *
800      * @see javax.sip.SipProvider#setListeningPoint(javax.sip.ListeningPoint)
801      */
setListeningPoint(ListeningPoint listeningPoint)802     public synchronized void setListeningPoint(ListeningPoint listeningPoint) {
803         if (listeningPoint == null)
804             throw new NullPointerException("Null listening point");
805         ListeningPointImpl lp = (ListeningPointImpl) listeningPoint;
806         lp.sipProvider = this;
807         String transport = lp.getTransport().toUpperCase();
808         this.address = listeningPoint.getIPAddress();
809         this.port = listeningPoint.getPort();
810         // This is the first listening point.
811         this.listeningPoints.clear();
812         this.listeningPoints.put(transport, listeningPoint);
813 
814     }
815 
816     /*
817      * (non-Javadoc)
818      *
819      * @see javax.sip.SipProvider#getNewDialog(javax.sip.Transaction)
820      */
821 
getNewDialog(Transaction transaction)822     public Dialog getNewDialog(Transaction transaction) throws SipException {
823         if (transaction == null)
824             throw new NullPointerException("Null transaction!");
825 
826         if (!sipStack.isAlive())
827             throw new SipException("Stack is stopped.");
828 
829         if (isAutomaticDialogSupportEnabled())
830             throw new SipException(" Error - AUTOMATIC_DIALOG_SUPPORT is on");
831 
832         if (!sipStack.isDialogCreated(transaction.getRequest().getMethod()))
833             throw new SipException("Dialog cannot be created for this method "
834                     + transaction.getRequest().getMethod());
835 
836         SIPDialog dialog = null;
837         SIPTransaction sipTransaction = (SIPTransaction) transaction;
838 
839         if (transaction instanceof ServerTransaction) {
840             SIPServerTransaction st = (SIPServerTransaction) transaction;
841             Response response = st.getLastResponse();
842             if (response != null) {
843                 if (response.getStatusCode() != 100)
844                     throw new SipException(
845                             "Cannot set dialog after response has been sent");
846             }
847             SIPRequest sipRequest = (SIPRequest) transaction.getRequest();
848             String dialogId = sipRequest.getDialogId(true);
849             dialog = sipStack.getDialog(dialogId);
850             if (dialog == null) {
851                 dialog = sipStack.createDialog((SIPTransaction) transaction);
852                 // create and register the dialog and add the inital route set.
853                 dialog.addTransaction(sipTransaction);
854                 dialog.addRoute(sipRequest);
855                 sipTransaction.setDialog(dialog, null);
856 
857             } else {
858                 sipTransaction.setDialog(dialog, sipRequest.getDialogId(true));
859             }
860             if (sipRequest.getMethod().equals(Request.INVITE) && this.isDialogErrorsAutomaticallyHandled()) {
861                 sipStack.putInMergeTable(st, sipRequest);
862             }
863         } else {
864 
865             SIPClientTransaction sipClientTx = (SIPClientTransaction) transaction;
866 
867             SIPResponse response = sipClientTx.getLastResponse();
868 
869             if (response == null) {
870                 // A response has not yet been received, then set this up as the
871                 // default dialog.
872                 SIPRequest request = (SIPRequest) sipClientTx.getRequest();
873 
874                 String dialogId = request.getDialogId(false);
875                 dialog = sipStack.getDialog(dialogId);
876                 if (dialog != null) {
877                     throw new SipException("Dialog already exists!");
878                 } else {
879                     dialog = sipStack.createDialog(sipTransaction);
880                 }
881                 sipClientTx.setDialog(dialog, null);
882 
883             } else {
884                 throw new SipException(
885                         "Cannot call this method after response is received!");
886             }
887         }
888         dialog.addEventListener(this);
889         return dialog;
890 
891     }
892 
893     /**
894      * Invoked when an error has ocurred with a transaction. Propagate up to the
895      * listeners.
896      *
897      * @param transactionErrorEvent
898      *            Error event.
899      */
transactionErrorEvent( SIPTransactionErrorEvent transactionErrorEvent)900     public void transactionErrorEvent(
901             SIPTransactionErrorEvent transactionErrorEvent) {
902         SIPTransaction transaction = (SIPTransaction) transactionErrorEvent
903                 .getSource();
904 
905         if (transactionErrorEvent.getErrorID() == SIPTransactionErrorEvent.TRANSPORT_ERROR) {
906             // There must be a way to inform the TU here!!
907             if (sipStack.isLoggingEnabled()) {
908                 sipStack.getStackLogger().logDebug(
909                         "TransportError occured on " + transaction);
910             }
911             // Treat this like a timeout event. (Suggestion from Christophe).
912             Object errorObject = transactionErrorEvent.getSource();
913             Timeout timeout = Timeout.TRANSACTION;
914             TimeoutEvent ev = null;
915 
916             if (errorObject instanceof SIPServerTransaction) {
917                 ev = new TimeoutEvent(this, (ServerTransaction) errorObject,
918                         timeout);
919             } else {
920                 SIPClientTransaction clientTx = (SIPClientTransaction) errorObject;
921                 Hop hop = clientTx.getNextHop();
922                 if ( sipStack.getRouter() instanceof RouterExt ) {
923                     ((RouterExt) sipStack.getRouter()).transactionTimeout(hop);
924                 }
925                 ev = new TimeoutEvent(this, (ClientTransaction) errorObject,
926                         timeout);
927             }
928             // Handling transport error like timeout
929             this.handleEvent(ev, (SIPTransaction) errorObject);
930         } else if (transactionErrorEvent.getErrorID() == SIPTransactionErrorEvent.TIMEOUT_ERROR) {
931             // This is a timeout event.
932             Object errorObject = transactionErrorEvent.getSource();
933             Timeout timeout = Timeout.TRANSACTION;
934             TimeoutEvent ev = null;
935 
936             if (errorObject instanceof SIPServerTransaction) {
937                 ev = new TimeoutEvent(this, (ServerTransaction) errorObject,
938                         timeout);
939             } else {
940                 SIPClientTransaction clientTx = (SIPClientTransaction) errorObject;
941                 Hop hop = clientTx.getNextHop();
942                 if ( sipStack.getRouter() instanceof RouterExt ) {
943                     ((RouterExt) sipStack.getRouter()).transactionTimeout(hop);
944                 }
945 
946                 ev = new TimeoutEvent(this, (ClientTransaction) errorObject,
947                         timeout);
948             }
949             this.handleEvent(ev, (SIPTransaction) errorObject);
950 
951         } else if (transactionErrorEvent.getErrorID() == SIPTransactionErrorEvent.TIMEOUT_RETRANSMIT) {
952             // This is a timeout retransmit event.
953             // We should never get this if retransmit filter is
954             // enabled (ie. in that case the stack should handle.
955             // all retransmits.
956             Object errorObject = transactionErrorEvent.getSource();
957             Transaction tx = (Transaction) errorObject;
958 
959             if (tx.getDialog() != null)
960                 InternalErrorHandler.handleException("Unexpected event !",
961                         this.sipStack.getStackLogger());
962 
963             Timeout timeout = Timeout.RETRANSMIT;
964             TimeoutEvent ev = null;
965 
966             if (errorObject instanceof SIPServerTransaction) {
967                 ev = new TimeoutEvent(this, (ServerTransaction) errorObject,
968                         timeout);
969             } else {
970                 ev = new TimeoutEvent(this, (ClientTransaction) errorObject,
971                         timeout);
972             }
973             this.handleEvent(ev, (SIPTransaction) errorObject);
974         }
975     }
976 
977     /*
978      * (non-Javadoc)
979      * @see gov.nist.javax.sip.stack.SIPDialogEventListener#dialogErrorEvent(gov.nist.javax.sip.stack.SIPDialogErrorEvent)
980      */
dialogErrorEvent(SIPDialogErrorEvent dialogErrorEvent)981     public synchronized void dialogErrorEvent(SIPDialogErrorEvent dialogErrorEvent) {
982         SIPDialog sipDialog = (SIPDialog) dialogErrorEvent.getSource();
983         Reason reason = Reason.AckNotReceived;
984         if (dialogErrorEvent.getErrorID() == SIPDialogErrorEvent.DIALOG_ACK_NOT_SENT_TIMEOUT) {
985         	reason= Reason.AckNotSent;
986         } else if (dialogErrorEvent.getErrorID() == SIPDialogErrorEvent.DIALOG_REINVITE_TIMEOUT) {
987             reason = Reason.ReInviteTimeout;
988         }
989         if (sipStack.isLoggingEnabled()) {
990             sipStack.getStackLogger().logDebug(
991                     "Dialog TimeoutError occured on " + sipDialog);
992         }
993         DialogTimeoutEvent ev = new DialogTimeoutEvent(this, sipDialog, reason);
994         // Handling transport error like timeout
995         this.handleEvent(ev, null);
996     }
997 
998     /*
999      * (non-Javadoc)
1000      *
1001      * @see javax.sip.SipProvider#getListeningPoints()
1002      */
getListeningPoints()1003     public synchronized ListeningPoint[] getListeningPoints() {
1004 
1005         ListeningPoint[] retval = new ListeningPointImpl[this.listeningPoints
1006                 .size()];
1007         this.listeningPoints.values().toArray(retval);
1008         return retval;
1009     }
1010 
1011     /*
1012      * (non-Javadoc)
1013      *
1014      * @see javax.sip.SipProvider#addListeningPoint(javax.sip.ListeningPoint)
1015      */
addListeningPoint(ListeningPoint listeningPoint)1016     public synchronized void addListeningPoint(ListeningPoint listeningPoint)
1017             throws ObjectInUseException {
1018         ListeningPointImpl lp = (ListeningPointImpl) listeningPoint;
1019         if (lp.sipProvider != null && lp.sipProvider != this)
1020             throw new ObjectInUseException(
1021                     "Listening point assigned to another provider");
1022         String transport = lp.getTransport().toUpperCase();
1023         if (this.listeningPoints.isEmpty()) {
1024             // first one -- record the IP address/port of the LP
1025 
1026             this.address = listeningPoint.getIPAddress();
1027             this.port = listeningPoint.getPort();
1028         } else {
1029             if ((!this.address.equals(listeningPoint.getIPAddress()))
1030                     || this.port != listeningPoint.getPort())
1031                 throw new ObjectInUseException(
1032                         "Provider already has different IP Address associated");
1033 
1034         }
1035         if (this.listeningPoints.containsKey(transport)
1036                 && this.listeningPoints.get(transport) != listeningPoint)
1037             throw new ObjectInUseException(
1038                     "Listening point already assigned for transport!");
1039 
1040         // This is for backwards compatibility.
1041         lp.sipProvider = this;
1042 
1043         this.listeningPoints.put(transport, lp);
1044 
1045     }
1046 
1047     /*
1048      * (non-Javadoc)
1049      *
1050      * @see javax.sip.SipProvider#removeListeningPoint(javax.sip.ListeningPoint)
1051      */
removeListeningPoint(ListeningPoint listeningPoint)1052     public synchronized void removeListeningPoint(ListeningPoint listeningPoint)
1053             throws ObjectInUseException {
1054         ListeningPointImpl lp = (ListeningPointImpl) listeningPoint;
1055         if (lp.messageProcessor.inUse())
1056             throw new ObjectInUseException("Object is in use");
1057         this.listeningPoints.remove(lp.getTransport().toUpperCase());
1058 
1059     }
1060 
1061     /**
1062      * Remove all the listening points for this sip provider. This is called
1063      * when the stack removes the Provider
1064      */
removeListeningPoints()1065     public synchronized void removeListeningPoints() {
1066         for (Iterator it = this.listeningPoints.values().iterator(); it
1067                 .hasNext();) {
1068             ListeningPointImpl lp = (ListeningPointImpl) it.next();
1069             lp.messageProcessor.stop();
1070             it.remove();
1071         }
1072 
1073     }
1074 
1075     /*
1076      * (non-Javadoc)
1077      *
1078      * @see javax.sip.SipProvider#setAutomaticDialogSupportEnabled(boolean)
1079      */
setAutomaticDialogSupportEnabled( boolean automaticDialogSupportEnabled)1080     public void setAutomaticDialogSupportEnabled(
1081             boolean automaticDialogSupportEnabled) {
1082         this.automaticDialogSupportEnabled = automaticDialogSupportEnabled;
1083         if ( this.automaticDialogSupportEnabled ) {
1084             this.dialogErrorsAutomaticallyHandled = true;
1085         }
1086     }
1087 
1088     /**
1089      * @return Returns the automaticDialogSupportEnabled.
1090      */
isAutomaticDialogSupportEnabled()1091     public boolean isAutomaticDialogSupportEnabled() {
1092         return automaticDialogSupportEnabled;
1093     }
1094 
1095     /*
1096      * (non-Javadoc)
1097      * @see gov.nist.javax.sip.SipProviderExt#setDialogErrorsAutomaticallyHandled()
1098      */
setDialogErrorsAutomaticallyHandled()1099     public void setDialogErrorsAutomaticallyHandled() {
1100         this.dialogErrorsAutomaticallyHandled = true;
1101     }
1102 
isDialogErrorsAutomaticallyHandled()1103     public boolean isDialogErrorsAutomaticallyHandled() {
1104         return this.dialogErrorsAutomaticallyHandled;
1105     }
1106 
1107 
1108     /**
1109      * @return the sipListener
1110      */
getSipListener()1111     public SipListener getSipListener() {
1112         return sipListener;
1113     }
1114 
1115 
1116 }
1117