Home | History | Annotate | Download | only in sip
      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 
    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      */
    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      */
    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 
    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 */
    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      */
    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      */
    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 
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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 
    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      */
    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      */
    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      */
   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      */
   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      */
   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      */
   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      */
   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      */
   1091     public boolean isAutomaticDialogSupportEnabled() {
   1092         return automaticDialogSupportEnabled;
   1093     }
   1094 
   1095     /*
   1096      * (non-Javadoc)
   1097      * @see gov.nist.javax.sip.SipProviderExt#setDialogErrorsAutomaticallyHandled()
   1098      */
   1099     public void setDialogErrorsAutomaticallyHandled() {
   1100         this.dialogErrorsAutomaticallyHandled = true;
   1101     }
   1102 
   1103     public boolean isDialogErrorsAutomaticallyHandled() {
   1104         return this.dialogErrorsAutomaticallyHandled;
   1105     }
   1106 
   1107 
   1108     /**
   1109      * @return the sipListener
   1110      */
   1111     public SipListener getSipListener() {
   1112         return sipListener;
   1113     }
   1114 
   1115 
   1116 }
   1117