Package gov.nist.javax.sip

Source Code of gov.nist.javax.sip.SipProviderImpl

/*
* Conditions Of Use
*
* This software was developed by employees of the National Institute of
* Standards and Technology (NIST), an agency of the Federal Government.
* Pursuant to title 15 Untied States Code Section 105, works of NIST
* employees are not subject to copyright protection in the United States
* and are considered to be in the public domain.  As a result, a formal
* license is not needed to use the software.
*
* This software is provided by NIST as a service and is expressly
* provided "AS IS."  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
* AND DATA ACCURACY.  NIST does not warrant or make any representations
* regarding the use of the software or the results thereof, including but
* not limited to the correctness, accuracy, reliability or usefulness of
* the software.
*
* Permission to use this software is contingent upon your acceptance
* of the terms of this agreement
*
* .
*
*/
/******************************************************************************
* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).      *
******************************************************************************/
package gov.nist.javax.sip;

import gov.nist.core.InternalErrorHandler;
import gov.nist.javax.sip.address.RouterExt;
import gov.nist.javax.sip.header.CallID;
import gov.nist.javax.sip.header.Via;
import gov.nist.javax.sip.message.SIPMessage;
import gov.nist.javax.sip.message.SIPRequest;
import gov.nist.javax.sip.message.SIPResponse;
import gov.nist.javax.sip.stack.HopImpl;
import gov.nist.javax.sip.stack.MessageChannel;
import gov.nist.javax.sip.stack.SIPClientTransaction;
import gov.nist.javax.sip.stack.SIPDialog;
import gov.nist.javax.sip.stack.SIPServerTransaction;
import gov.nist.javax.sip.stack.SIPTransaction;
import gov.nist.javax.sip.stack.SIPTransactionErrorEvent;
import gov.nist.javax.sip.stack.SIPTransactionEventListener;

import java.io.IOException;
import java.text.ParseException;
import java.util.EventObject;
import java.util.Iterator;
import java.util.TooManyListenersException;
import java.util.concurrent.ConcurrentHashMap;

import javax.sip.ClientTransaction;
import javax.sip.Dialog;
import javax.sip.DialogState;
import javax.sip.InvalidArgumentException;
import javax.sip.ListeningPoint;
import javax.sip.ObjectInUseException;
import javax.sip.RequestEvent;
import javax.sip.ResponseEvent;
import javax.sip.ServerTransaction;
import javax.sip.SipException;
import javax.sip.SipListener;
import javax.sip.SipStack;
import javax.sip.Timeout;
import javax.sip.TimeoutEvent;
import javax.sip.Transaction;
import javax.sip.TransactionAlreadyExistsException;
import javax.sip.TransactionState;
import javax.sip.TransactionUnavailableException;
import javax.sip.address.Hop;
import javax.sip.header.CallIdHeader;
import javax.sip.message.Request;
import javax.sip.message.Response;

/*
* Contributions (bug fixes) made by: Daniel J. Martinez Manzano, Hagai Sela.
* Bug reports by Shanti Kadiyala, Rhys Ulerich,Victor Hugo
*/
/**
* Implementation of the JAIN-SIP provider interface.
*
* @version 1.2 $Revision: 1.61 $ $Date: 2009/05/20 06:10:01 $
*
* @author M. Ranganathan <br/>
*
*
*/

public final class SipProviderImpl implements javax.sip.SipProvider,
    SIPTransactionEventListener {

  protected SipListener sipListener;

  protected SipStackImpl sipStack;

  /*
   * A set of listening points associated with the provider At most one LP per
   * transport
   */
  private ConcurrentHashMap listeningPoints;

  private EventScanner eventScanner;

  private String address;

  private int port;

  private boolean automaticDialogSupportEnabled;

  /**
   * A string containing the 0.0.0.0 IPv4 ANY address.
   */
  private String IN_ADDR_ANY = "0.0.0.0";

  /**
   * A string containing the ::0 IPv6 ANY address.
   */
  private String IN6_ADDR_ANY = "::0"
 
  /**
   * Stop processing messages for this provider. Post an empty message to our
   * message processing queue that signals us to quit.
   */
  protected void stop() {
    // Put an empty event in the queue and post ourselves a message.
    if (sipStack.isLoggingEnabled())
      sipStack.getLogWriter().logDebug("Exiting provider");
    for (Iterator it = listeningPoints.values().iterator(); it.hasNext();) {
      ListeningPointImpl listeningPoint = (ListeningPointImpl) it.next();
      listeningPoint.removeSipProvider();
    }
    this.eventScanner.stop();

  }

  /*
   * (non-Javadoc)
   *
   * @see javax.sip.SipProvider#getListeningPoint(java.lang.String)
   */
  public ListeningPoint getListeningPoint(String transport) {
    if (transport == null)
      throw new NullPointerException("Null transport param");
    return (ListeningPoint) this.listeningPoints.get(transport
        .toUpperCase());
  }

  /**
   * Handle the SIP event - because we have only one listener and we are
   * already in the context of a separate thread, we dont need to enque the
   * event and signal another thread.
   *
   * @param sipEvent
   *            is the event to process.
   *
   */

  public void handleEvent(EventObject sipEvent, SIPTransaction transaction) {
    if (sipStack.isLoggingEnabled()) {
      sipStack.getLogWriter().logDebug(
          "handleEvent " + sipEvent + "currentTransaction = "
              + transaction + "this.sipListener = "
              + this.sipListener + "sipEvent.source = "
              + sipEvent.getSource());
      if (sipEvent instanceof RequestEvent) {
        Dialog dialog = ((RequestEvent) sipEvent).getDialog();
        if ( sipStack.isLoggingEnabled())  sipStack.getLogWriter().logDebug("Dialog = " + dialog);
      } else if (sipEvent instanceof ResponseEvent) {
        Dialog dialog = ((ResponseEvent) sipEvent).getDialog();
        if (sipStack.isLoggingEnabled() ) sipStack.getLogWriter().logDebug("Dialog = " + dialog);
      }
      sipStack.getLogWriter().logStackTrace();
    }

    EventWrapper eventWrapper = new EventWrapper(sipEvent, transaction);

    if (!sipStack.reEntrantListener) {
      // Run the event in the context of a single thread.
      this.eventScanner.addEvent(eventWrapper);
    } else {
      // just call the delivery method
      this.eventScanner.deliverEvent(eventWrapper);
    }
  }

  /** Creates a new instance of SipProviderImpl */
  protected SipProviderImpl(SipStackImpl sipStack) {
    this.eventScanner = sipStack.getEventScanner(); // for quick access.
    this.sipStack = sipStack;
    this.eventScanner.incrementRefcount();
    this.listeningPoints = new ConcurrentHashMap<String,ListeningPointImpl>();
    this.automaticDialogSupportEnabled = this.sipStack
        .isAutomaticDialogSupportEnabled();
  }

  /*
   * (non-Javadoc)
   *
   * @see java.lang.Object#clone()
   */
  protected Object clone() throws java.lang.CloneNotSupportedException {
    throw new java.lang.CloneNotSupportedException();
  }

  /*
   * (non-Javadoc)
   *
   * @see java.lang.Object#equals(java.lang.Object)
   */
  public boolean equals(Object obj) {
    return super.equals(obj);
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.sip.SipProvider#addSipListener(javax.sip.SipListener)
   */
  public void addSipListener(SipListener sipListener)
      throws TooManyListenersException {

    if (sipStack.sipListener == null) {
      sipStack.sipListener = sipListener;
    } else if (sipStack.sipListener != sipListener) {
      throw new TooManyListenersException(
          "Stack already has a listener. Only one listener per stack allowed");
    }

    if (sipStack.isLoggingEnabled())
      sipStack.getLogWriter().logDebug("add SipListener " + sipListener);
    this.sipListener = sipListener;

  }

  /*
   * This method is deprecated (non-Javadoc)
   *
   * @see javax.sip.SipProvider#getListeningPoint()
   */

  public ListeningPoint getListeningPoint() {
    if (this.listeningPoints.size() > 0)
      return (ListeningPoint) this.listeningPoints.values().iterator()
          .next();
    else
      return null;
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.sip.SipProvider#getNewCallId()
   */
  public CallIdHeader getNewCallId() {
    String callId = Utils.getInstance().generateCallIdentifier(this.getListeningPoint()
        .getIPAddress());
    CallID callid = new CallID();
    try {
      callid.setCallId(callId);
    } catch (java.text.ParseException ex) {
    }
    return callid;

  }

  /*
   * (non-Javadoc)
   *
   * @see javax.sip.SipProvider#getNewClientTransaction(javax.sip.message.Request)
   */
  public ClientTransaction getNewClientTransaction(Request request)
      throws TransactionUnavailableException {
    if (request == null)
      throw new NullPointerException("null request");
    if (!sipStack.isAlive())
      throw new TransactionUnavailableException("Stack is stopped");

    SIPRequest sipRequest = (SIPRequest) request;
    if (sipRequest.getTransaction() != null)
      throw new TransactionUnavailableException(
          "Transaction already assigned to request");
    if ( sipRequest.getMethod().equals(Request.ACK)) {
      throw new TransactionUnavailableException ("Cannot create client transaction for  " + Request.ACK);
    }
    // Be kind and assign a via header for this provider if the user is
    // sloppy
    if (sipRequest.getTopmostVia() == null) {
      ListeningPointImpl lp = (ListeningPointImpl) this
          .getListeningPoint("udp");
      Via via = lp.getViaHeader();
      request.setHeader(via);
    }
    // Give the request a quick check to see if all headers are assigned.
    try {
      sipRequest.checkHeaders();
    } catch (ParseException ex) {
      throw new TransactionUnavailableException(ex.getMessage(), ex);
    }

    /*
     * User decided to give us his own via header branch. Lets see if it
     * results in a clash. If so reject the request.
     */
    if (sipRequest.getTopmostVia().getBranch() != null
        && sipRequest.getTopmostVia().getBranch().startsWith(
            SIPConstants.BRANCH_MAGIC_COOKIE)
        && sipStack.findTransaction((SIPRequest) request, false) != null) {
      throw new TransactionUnavailableException(
          "Transaction already exists!");
    }

   
   

    if (request.getMethod().equalsIgnoreCase(Request.CANCEL)) {
      SIPClientTransaction ct = (SIPClientTransaction) sipStack
          .findCancelTransaction((SIPRequest) request, false);
      if (ct != null) {
        ClientTransaction retval = sipStack.createClientTransaction(
            (SIPRequest) request, ct.getMessageChannel());

        ((SIPTransaction) retval).addEventListener(this);
        sipStack.addTransaction((SIPClientTransaction) retval);
        if (ct.getDialog() != null) {
          ((SIPClientTransaction) retval).setDialog((SIPDialog) ct
              .getDialog(), sipRequest.getDialogId(false));

        }
        return retval;
      }

    }
    if (sipStack.isLoggingEnabled())
      sipStack.getLogWriter().logDebug(
          "could not find existing transaction for "
              + ((SIPRequest) request).getFirstLine()
              + " creating a new one ");

    // Could not find a dialog or the route is not set in dialog.

    Hop hop = null;
    try {
      hop = sipStack.getNextHop((SIPRequest) request);
      if (hop == null)
        throw new TransactionUnavailableException(
            "Cannot resolve next hop -- transaction unavailable");
    } catch (SipException ex) {
      throw new TransactionUnavailableException(
          "Cannot resolve next hop -- transaction unavailable", ex);
    }
    String transport = hop.getTransport();
        ListeningPointImpl listeningPoint = (ListeningPointImpl) this
                .getListeningPoint(transport);
       
    String dialogId = sipRequest.getDialogId(false);
    SIPDialog dialog = sipStack.getDialog(dialogId);
    if (dialog != null && dialog.getState() == DialogState.TERMINATED) {

      // throw new TransactionUnavailableException
      // ("Found a terminated dialog -- possible re-use of old tag
      // parameters");
      sipStack.removeDialog(dialog);

    }

    // An out of dialog route was found. Assign this to the
    // client transaction.

    try {
      // Set the brannch id before you ask for a tx.
      // If the user has set his own branch Id and the
      // branch id starts with a valid prefix, then take it.
      // otherwise, generate one.
      String branchId = null;
      if (sipRequest.getTopmostVia().getBranch() == null
          || !sipRequest.getTopmostVia().getBranch().startsWith(
              SIPConstants.BRANCH_MAGIC_COOKIE)) {
        branchId = Utils.getInstance().generateBranchId();

        sipRequest.getTopmostVia().setBranch(branchId);
      }
      Via topmostVia = sipRequest.getTopmostVia();
          topmostVia.setTransport(transport);
          topmostVia.setPort(listeningPoint.getPort());
      branchId = sipRequest.getTopmostVia().getBranch();
     
      SIPClientTransaction ct = (SIPClientTransaction) sipStack
          .createMessageChannel(sipRequest, listeningPoint
              .getMessageProcessor(), hop);
      if (ct == null)
        throw new TransactionUnavailableException("Cound not create tx");
      ct.setNextHop(hop);
      ct.setOriginalRequest(sipRequest);
      ct.setBranch(branchId);
      // if the stack supports dialogs then
      if (sipStack.isDialogCreated(request.getMethod())) {
        // create a new dialog to contain this transaction
        // provided this is necessary.
        // This could be a re-invite
        // in which case the dialog is re-used.
        // (but noticed by Brad Templeton)
        if (dialog != null)
          ct.setDialog(dialog, sipRequest.getDialogId(false));
        else if (this.isAutomaticDialogSupportEnabled()) {
          SIPDialog sipDialog = sipStack.createDialog(ct);
          ct.setDialog(sipDialog, sipRequest.getDialogId(false));
        }
      } else {
        if (dialog != null) {
          ct.setDialog(dialog, sipRequest.getDialogId(false));
        }

      }

      // The provider is the event listener for all transactions.
      ct.addEventListener(this);
      return (ClientTransaction) ct;
    } catch (IOException ex) {

      throw new TransactionUnavailableException(
          "Could not resolve next hop or listening point unavailable! ",
          ex);

    } catch (java.text.ParseException ex) {
      InternalErrorHandler.handleException(ex);
      throw new TransactionUnavailableException(
          "Unexpected Exception FIXME! ", ex);
    } catch (InvalidArgumentException ex) {
        InternalErrorHandler.handleException(ex);
            throw new TransactionUnavailableException(
                    "Unexpected Exception FIXME! ", ex);
    }

  }

  /*
   * (non-Javadoc)
   *
   * @see javax.sip.SipProvider#getNewServerTransaction(javax.sip.message.Request)
   */
  public ServerTransaction getNewServerTransaction(Request request)
      throws TransactionAlreadyExistsException,
      TransactionUnavailableException {

    if (!sipStack.isAlive())
      throw new TransactionUnavailableException("Stack is stopped");
    SIPServerTransaction transaction = null;
    SIPRequest sipRequest = (SIPRequest) request;
    try {
      sipRequest.checkHeaders();
    } catch (ParseException ex) {
      throw new TransactionUnavailableException(ex.getMessage(), ex);
    }

    if ( request.getMethod().equals(Request.ACK)) {
      if ( sipStack.isLoggingEnabled())
        sipStack.getLogWriter().logError("Creating server transaction for ACK -- makes no sense!");
      throw new TransactionUnavailableException("Cannot create Server transaction for ACK ");
    }
    /*
     * Got a notify.
     */
    if (sipRequest.getMethod().equals(Request.NOTIFY)
        && sipRequest.getFromTag() != null
        && sipRequest.getToTag() == null) {

      SIPClientTransaction ct = sipStack.findSubscribeTransaction(
          sipRequest, (ListeningPointImpl) this.getListeningPoint());
      /* Issue 104 */
      if (ct == null && ! sipStack.deliverUnsolicitedNotify) {
        throw new TransactionUnavailableException(
            "Cannot find matching Subscription (and gov.nist.javax.sip.DELIVER_UNSOLICITED_NOTIFY not set)");
      }
    }
    if (sipStack.isDialogCreated(sipRequest.getMethod())) {
      if (sipStack.findTransaction((SIPRequest) request, true) != null)
        throw new TransactionAlreadyExistsException(
            "server transaction already exists!");

      transaction = (SIPServerTransaction) ((SIPRequest) request)
          .getTransaction();
      if (transaction == null)
        throw new TransactionUnavailableException(
            "Transaction not available");
      if (transaction.getOriginalRequest() == null)
        transaction.setOriginalRequest(sipRequest);
      try {
        sipStack.addTransaction(transaction);
      } catch (IOException ex) {
        throw new TransactionUnavailableException(
            "Error sending provisional response");
      }
      // So I can handle timeouts.
      transaction.addEventListener(this);
      if (isAutomaticDialogSupportEnabled()) {
        // If automatic dialog support is enabled then
        // this tx gets his own dialog.
        String dialogId = sipRequest.getDialogId(true);
        SIPDialog dialog = sipStack.getDialog(dialogId);
        if (dialog == null) {
          dialog = sipStack.createDialog(transaction);

        }
        transaction.setDialog(dialog, sipRequest.getDialogId(true));
        if (sipStack.isDialogCreated(sipRequest.getMethod())) {
          sipStack.putInMergeTable(transaction, sipRequest);
        }
        dialog.addRoute(sipRequest);
        if (dialog.getRemoteTag() != null
            && dialog.getLocalTag() != null) {
          this.sipStack.putDialog(dialog);
        }
      }

    } else {
      if (isAutomaticDialogSupportEnabled()) {
        // Under autmatic dialog support, dialog is tied into a
        // transaction.
        // You cannot create a server tx except for dialog creating
        // transactions.
        // After that, all subsequent transactions are created for you
        // by the stack.
        transaction = (SIPServerTransaction) sipStack.findTransaction(
            (SIPRequest) request, true);
        if (transaction != null)
          throw new TransactionAlreadyExistsException(
              "Transaction exists! ");
        transaction = (SIPServerTransaction) ((SIPRequest) request)
            .getTransaction();
        if (transaction == null)
          throw new TransactionUnavailableException(
              "Transaction not available!");
        if (transaction.getOriginalRequest() == null)
          transaction.setOriginalRequest(sipRequest);
        // Map the transaction.
        try {
          sipStack.addTransaction(transaction);
        } catch (IOException ex) {
          throw new TransactionUnavailableException(
              "Could not send back provisional response!");
        }

        // If there is a dialog already assigned then just update the
        // dialog state.
        String dialogId = sipRequest.getDialogId(true);
        SIPDialog dialog = sipStack.getDialog(dialogId);
        if (dialog != null) {
          dialog.addTransaction(transaction);
          dialog.addRoute(sipRequest);
          transaction.setDialog(dialog, sipRequest.getDialogId(true));
        }

      } else {
        transaction = (SIPServerTransaction) sipStack.findTransaction(
            (SIPRequest) request, true);
        if (transaction != null)
          throw new TransactionAlreadyExistsException(
              "Transaction exists! ");
        transaction = (SIPServerTransaction) ((SIPRequest) request)
            .getTransaction();
        if (transaction != null) {
          if (transaction.getOriginalRequest() == null)
            transaction.setOriginalRequest(sipRequest);
          // Map the transaction.
          sipStack.mapTransaction(transaction);

          // If there is a dialog already assigned then just
          // assign the dialog to the transaction.
          String dialogId = sipRequest.getDialogId(true);
          SIPDialog dialog = sipStack.getDialog(dialogId);
          if (dialog != null) {
            dialog.addTransaction(transaction);
            dialog.addRoute(sipRequest);
            transaction.setDialog(dialog, sipRequest
                .getDialogId(true));
          }

          return transaction;
        } else {
          // tx does not exist so create the tx.

          MessageChannel mc = (MessageChannel) sipRequest
              .getMessageChannel();
          transaction = sipStack.createServerTransaction(mc);
          if (transaction == null)
            throw new TransactionUnavailableException(
                "Transaction unavailable -- too many servrer transactions");

          transaction.setOriginalRequest(sipRequest);
          sipStack.mapTransaction(transaction);

          // If there is a dialog already assigned then just
          // assign the dialog to the transaction.
          String dialogId = sipRequest.getDialogId(true);
          SIPDialog dialog = sipStack.getDialog(dialogId);
          if (dialog != null) {
            dialog.addTransaction(transaction);
            dialog.addRoute(sipRequest);
            transaction.setDialog(dialog, sipRequest
                .getDialogId(true));
          }

          return transaction;
        }
      }

    }
    return transaction;

  }

  /*
   * (non-Javadoc)
   *
   * @see javax.sip.SipProvider#getSipStack()
   */
  public SipStack getSipStack() {
    return (SipStack) this.sipStack;
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.sip.SipProvider#removeSipListener(javax.sip.SipListener)
   */
  public void removeSipListener(SipListener sipListener) {
    if (sipListener == this.sipListener) {
      this.sipListener = null;
    }

    boolean found = false;

    for (Iterator<SipProviderImpl> it = sipStack.getSipProviders(); it.hasNext();) {
      SipProviderImpl nextProvider = (SipProviderImpl) it.next();
      if (nextProvider.sipListener != null)
        found = true;
    }
    if (!found) {
      sipStack.sipListener = null;
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.sip.SipProvider#sendRequest(javax.sip.message.Request)
   */
  public void sendRequest(Request request) throws SipException {
    if (!sipStack.isAlive())
      throw new SipException("Stack is stopped.");

    // mranga: added check to ensure we are not sending empty (keepalive)
    // message.
    if (((SIPRequest) request).getRequestLine() != null
        && request.getMethod().equals(Request.ACK)) {
      Dialog dialog = sipStack.getDialog(((SIPRequest) request)
          .getDialogId(false));
      if (dialog != null && dialog.getState() != null) {
        sipStack.getLogWriter().logWarning(
            "Dialog exists -- you may want to use Dialog.sendAck() "
                + dialog.getState());
      }
    }
    Hop hop = sipStack.getRouter((SIPRequest) request).getNextHop(request);
    if (hop == null)
      throw new SipException("could not determine next hop!");
    SIPRequest sipRequest = (SIPRequest) request;
    // Check if we have a valid via.
    // Null request is used to send default proxy keepalive messages.
    if ((!sipRequest.isNullRequest()) && sipRequest.getTopmostVia() == null)
      throw new SipException("Invalid SipRequest -- no via header!");

    try {
      /*
       * JvB: Via branch should already be OK, dont touch it here? Some
       * apps forward statelessly, and then it's not set. So set only when
       * not set already, dont overwrite CANCEL branch here..
       */
      if (!sipRequest.isNullRequest()) {
        Via via = sipRequest.getTopmostVia();
        String branch = via.getBranch();
        if (branch == null || branch.length() == 0) {
          via.setBranch(sipRequest.getTransactionId());
        }
      }
      MessageChannel messageChannel = null;
      if (this.listeningPoints.containsKey(hop.getTransport()
          .toUpperCase()))
        messageChannel = sipStack.createRawMessageChannel(
            this.getListeningPoint(hop.getTransport()).getIPAddress(),
            this.getListeningPoint(hop.getTransport()).getPort(), hop);
      if (messageChannel != null) {
        messageChannel.sendMessage((SIPMessage) sipRequest,hop);
      } else {
        throw new SipException(
            "Could not create a message channel for "
                + hop.toString());
      }
    } catch (IOException ex) {
      if (sipStack.isLoggingEnabled()) {
        sipStack.getLogWriter().logException(ex);
      }

      throw new SipException(
          "IO Exception occured while Sending Request", ex);

    } catch (ParseException ex1) {
      InternalErrorHandler.handleException(ex1);
    } finally {
      if (sipStack.isLoggingEnabled())
        sipStack.getLogWriter().logDebug(
            "done sending " + request.getMethod() + " to hop "
                + hop);
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.sip.SipProvider#sendResponse(javax.sip.message.Response)
   */
  public void sendResponse(Response response) throws SipException {
    if (!sipStack.isAlive())
      throw new SipException("Stack is stopped");
    SIPResponse sipResponse = (SIPResponse) response;
    Via via = sipResponse.getTopmostVia();
    if (via == null)
      throw new SipException("No via header in response!");
    SIPServerTransaction st = (SIPServerTransaction) sipStack.findTransaction((SIPMessage)response, true);
    if ( st != null   && st.getState() != TransactionState.TERMINATED && this.isAutomaticDialogSupportEnabled()) {
      throw new SipException("Transaction exists -- cannot send response statelessly");
    }
    String transport = via.getTransport();

    // check to see if Via has "received paramaeter". If so
    // set the host to the via parameter. Else set it to the
    // Via host.
    String host = via.getReceived();

    if (host == null)
      host = via.getHost();

    // Symmetric nat support
    int port = via.getRPort();
    if (port == -1) {
      port = via.getPort();
      if (port == -1) {
        if (transport.equalsIgnoreCase("TLS"))
          port = 5061;
        else
          port = 5060;
      }
    }

    // for correct management of IPv6 addresses.
    if (host.indexOf(":") > 0)
      if (host.indexOf("[") < 0)
        host = "[" + host + "]";

    Hop hop = sipStack.getAddressResolver().resolveAddress(
        new HopImpl(host, port, transport));

    try {
      ListeningPointImpl listeningPoint = (ListeningPointImpl) this
          .getListeningPoint(transport);
      if (listeningPoint == null)
        throw new SipException(
            "whoopsa daisy! no listening point found for transport "
                + transport);
      MessageChannel messageChannel = sipStack.createRawMessageChannel(
          this.getListeningPoint(hop.getTransport()).getIPAddress(),
          listeningPoint.port, hop);
      messageChannel.sendMessage(sipResponse);
    } catch (IOException ex) {
      throw new SipException(ex.getMessage());
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.sip.SipProvider#setListeningPoint(javax.sip.ListeningPoint)
   */
  public synchronized void setListeningPoint(ListeningPoint listeningPoint) {
    if (listeningPoint == null)
      throw new NullPointerException("Null listening point");
    ListeningPointImpl lp = (ListeningPointImpl) listeningPoint;
    lp.sipProvider = this;
    String transport = lp.getTransport().toUpperCase();
    this.address = listeningPoint.getIPAddress();
    this.port = listeningPoint.getPort();
    // This is the first listening point.
    this.listeningPoints.clear();
    this.listeningPoints.put(transport, listeningPoint);

  }

  /*
   * (non-Javadoc)
   *
   * @see javax.sip.SipProvider#getNewDialog(javax.sip.Transaction)
   */

  public Dialog getNewDialog(Transaction transaction) throws SipException {
    if (transaction == null)
      throw new NullPointerException("Null transaction!");

    if (!sipStack.isAlive())
      throw new SipException("Stack is stopped.");

    if (isAutomaticDialogSupportEnabled())
      throw new SipException(" Error - AUTOMATIC_DIALOG_SUPPORT is on");

    if (!sipStack.isDialogCreated(transaction.getRequest().getMethod()))
      throw new SipException("Dialog cannot be created for this method "
          + transaction.getRequest().getMethod());

    SIPDialog dialog = null;
    SIPTransaction sipTransaction = (SIPTransaction) transaction;

    if (transaction instanceof ServerTransaction) {
      SIPServerTransaction st = (SIPServerTransaction) transaction;
      Response response = st.getLastResponse();
      if (response != null) {
        if (response.getStatusCode() != 100)
          throw new SipException(
              "Cannot set dialog after response has been sent");
      }
      SIPRequest sipRequest = (SIPRequest) transaction.getRequest();
      String dialogId = sipRequest.getDialogId(true);
      dialog = sipStack.getDialog(dialogId);
      if (dialog == null) {
        dialog = sipStack.createDialog((SIPTransaction) transaction);
        // create and register the dialog and add the inital route set.
        dialog.addTransaction(sipTransaction);
        dialog.addRoute(sipRequest);
        sipTransaction.setDialog(dialog, null);

      } else {
        sipTransaction.setDialog(dialog, sipRequest.getDialogId(true));
      }
      if (sipStack.isDialogCreated(sipRequest.getMethod())) {
        sipStack.putInMergeTable(st, sipRequest);
      }
    } else {

      SIPClientTransaction sipClientTx = (SIPClientTransaction) transaction;

      SIPResponse response = sipClientTx.getLastResponse();

      if (response == null) {
        // A response has not yet been received, then set this up as the
        // default dialog.
        SIPRequest request = (SIPRequest) sipClientTx.getRequest();

        String dialogId = request.getDialogId(false);
        dialog = sipStack.getDialog(dialogId);
        if (dialog != null) {
          throw new SipException("Dialog already exists!");
        } else {
          dialog = sipStack.createDialog(sipTransaction);
        }
        sipClientTx.setDialog(dialog, null);

      } else {
        throw new SipException(
            "Cannot call this method after response is received!");
      }
    }
    return dialog;

  }

  /**
   * Invoked when an error has ocurred with a transaction. Propagate up to the
   * listeners.
   *
   * @param transactionErrorEvent
   *            Error event.
   */
  public void transactionErrorEvent(
      SIPTransactionErrorEvent transactionErrorEvent) {
    SIPTransaction transaction = (SIPTransaction) transactionErrorEvent
        .getSource();

    if (transactionErrorEvent.getErrorID() == SIPTransactionErrorEvent.TRANSPORT_ERROR) {
      // There must be a way to inform the TU here!!
      if (sipStack.isLoggingEnabled()) {
        sipStack.getLogWriter().logDebug(
            "TransportError occured on " + transaction);
      }
      // Treat this like a timeout event. (Suggestion from Christophe).
      Object errorObject = transactionErrorEvent.getSource();
      Timeout timeout = Timeout.TRANSACTION;
      TimeoutEvent ev = null;

      if (errorObject instanceof SIPServerTransaction) {
        ev = new TimeoutEvent(this, (ServerTransaction) errorObject,
            timeout);
      } else {
          SIPClientTransaction clientTx = (SIPClientTransaction) errorObject;
          Hop hop = clientTx.getNextHop();
          if ( sipStack.getRouter() instanceof RouterExt ) {
              ((RouterExt) sipStack.getRouter()).transactionTimeout(hop);
          }
        ev = new TimeoutEvent(this, (ClientTransaction) errorObject,
            timeout);
      }
      // Handling transport error like timeout
      this.handleEvent(ev, (SIPTransaction) errorObject);
    } else if (transactionErrorEvent.getErrorID() == SIPTransactionErrorEvent.TIMEOUT_ERROR) {
      // This is a timeout event.
      Object errorObject = transactionErrorEvent.getSource();
      Timeout timeout = Timeout.TRANSACTION;
      TimeoutEvent ev = null;

      if (errorObject instanceof SIPServerTransaction) {
        ev = new TimeoutEvent(this, (ServerTransaction) errorObject,
            timeout);
      } else {
          SIPClientTransaction clientTx = (SIPClientTransaction) errorObject;
                Hop hop = clientTx.getNextHop();
                if ( sipStack.getRouter() instanceof RouterExt ) {
                    ((RouterExt) sipStack.getRouter()).transactionTimeout(hop);
                }
           
        ev = new TimeoutEvent(this, (ClientTransaction) errorObject,
            timeout);
      }
      this.handleEvent(ev, (SIPTransaction) errorObject);

    } else if (transactionErrorEvent.getErrorID() == SIPTransactionErrorEvent.TIMEOUT_RETRANSMIT) {
      // This is a timeout retransmit event.
      // We should never get this if retransmit filter is
      // enabled (ie. in that case the stack should handle.
      // all retransmits.
      Object errorObject = transactionErrorEvent.getSource();
      Transaction tx = (Transaction) errorObject;

      if (tx.getDialog() != null)
        InternalErrorHandler.handleException("Unexpected event !",
            this.sipStack.getLogWriter());

      Timeout timeout = Timeout.RETRANSMIT;
      TimeoutEvent ev = null;

      if (errorObject instanceof SIPServerTransaction) {
        ev = new TimeoutEvent(this, (ServerTransaction) errorObject,
            timeout);
      } else {
        ev = new TimeoutEvent(this, (ClientTransaction) errorObject,
            timeout);
      }
      this.handleEvent(ev, (SIPTransaction) errorObject);
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.sip.SipProvider#getListeningPoints()
   */
  public synchronized ListeningPoint[] getListeningPoints() {

    ListeningPoint[] retval = new ListeningPointImpl[this.listeningPoints
        .size()];
    this.listeningPoints.values().toArray(retval);
    return retval;
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.sip.SipProvider#addListeningPoint(javax.sip.ListeningPoint)
   */
  public synchronized void addListeningPoint(ListeningPoint listeningPoint)
      throws ObjectInUseException {
    ListeningPointImpl lp = (ListeningPointImpl) listeningPoint;
    if (lp.sipProvider != null && lp.sipProvider != this)
      throw new ObjectInUseException(
          "Listening point assigned to another provider");
    String transport = lp.getTransport().toUpperCase();
    if (this.listeningPoints.isEmpty()) {
      // first one -- record the IP address/port of the LP

      this.address = listeningPoint.getIPAddress();
      this.port = listeningPoint.getPort();
    } else {
      if ((!this.address.equals(listeningPoint.getIPAddress()))
          || this.port != listeningPoint.getPort())
        throw new ObjectInUseException(
            "Provider already has different IP Address associated");

    }
    if (this.listeningPoints.containsKey(transport)
        && this.listeningPoints.get(transport) != listeningPoint)
      throw new ObjectInUseException(
          "Listening point already assigned for transport!");

    // This is for backwards compatibility.
    lp.sipProvider = this;

    this.listeningPoints.put(transport, lp);

  }

  /*
   * (non-Javadoc)
   *
   * @see javax.sip.SipProvider#removeListeningPoint(javax.sip.ListeningPoint)
   */
  public synchronized void removeListeningPoint(ListeningPoint listeningPoint)
      throws ObjectInUseException {
    ListeningPointImpl lp = (ListeningPointImpl) listeningPoint;
    if (lp.messageProcessor.inUse())
      throw new ObjectInUseException("Object is in use");
    this.listeningPoints.remove(lp.getTransport().toUpperCase());

  }

  /**
   * Remove all the listening points for this sip provider. This is called
   * when the stack removes the Provider
   */
  public synchronized void removeListeningPoints() {
    for (Iterator it = this.listeningPoints.values().iterator(); it
        .hasNext();) {
      ListeningPointImpl lp = (ListeningPointImpl) it.next();
      lp.messageProcessor.stop();
      it.remove();
    }

  }

  /*
   * (non-Javadoc)
   *
   * @see javax.sip.SipProvider#setAutomaticDialogSupportEnabled(boolean)
   */
  public void setAutomaticDialogSupportEnabled(
      boolean automaticDialogSupportEnabled) {
    this.automaticDialogSupportEnabled = automaticDialogSupportEnabled;
  }

  /**
   * @return Returns the automaticDialogSupportEnabled.
   */
  public boolean isAutomaticDialogSupportEnabled() {
    return automaticDialogSupportEnabled;
  }

 

}
TOP

Related Classes of gov.nist.javax.sip.SipProviderImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.