Package gov.nist.javax.sip.stack

Source Code of gov.nist.javax.sip.stack.DefaultRouter

/*
* 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.stack;

import gov.nist.javax.sip.message.*;
import gov.nist.javax.sip.address.*;
import gov.nist.javax.sip.header.*;
import gov.nist.javax.sip.*;
import gov.nist.core.*;
import gov.nist.core.net.AddressResolver;

import javax.sip.*;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.ListIterator;

import javax.sip.header.RouteHeader;
import javax.sip.header.ViaHeader;
import javax.sip.message.*;
import javax.sip.address.*;

/*
* Bug reported by Will Scullin -- maddr was being ignored when routing
* requests. Bug reported by Antonis Karydas - the RequestURI can be a non-sip
* URI Jiang He - use address in route header. Significant changes to conform to
* RFC 3261 made by Jeroen van Bemmel. Hagai Sela contributed a bug fix to the
* strict route post processing code.
*
*/

/**
* This is the default router. When the implementation wants to forward a
* request and had run out of othe options, then it calls this method to figure
* out where to send the request. The default router implements a simple
* "default routing algorithm" which just forwards to the configured proxy
* address.
*
* <p>
* When <code>javax.sip.USE_ROUTER_FOR_ALL_URIS</code> is set to
* <code>false</code>, the next hop is determined according to the following
* algorithm:
* <ul>
* <li> If the request contains one or more Route headers, use the URI of the
* topmost Route header as next hop, possibly modifying the request in the
* process if the topmost Route header contains no lr parameter(*)
* <li> Else, if the property <code>javax.sip.OUTBOUND_PROXY</code> is set,
* use its value as the next hop
* <li> Otherwise, use the request URI as next hop. If the request URI is not a
* SIP URI, call {@link javax.sip.address.Router#getNextHop(Request)} provided
* by the application.
* </ul>
*
* <p>
* (*)Note that in case the topmost Route header contains no 'lr' parameter
* (which means the next hop is a strict router), the implementation will
* perform 'Route Information Postprocessing' as described in RFC3261 section
* 16.6 step 6 (also known as "Route header popping"). That is, the following
* modifications will be made to the request:
* <ol>
* <li>The implementation places the Request-URI into the Route header field as
* the last value.
* <li>The implementation then places the first Route header field value into
* the Request-URI and removes that value from the Route header field.
* </ol>
* Subsequently, the request URI will be used as next hop target
*
*
* @version 1.2 $Revision: 1.13 $ $Date: 2008/11/03 14:12:08 $
*
* @author M. Ranganathan <br/>
*
*/
public class DefaultRouter implements Router {

  private SipStackImpl sipStack;

  private Hop defaultRoute;

  private DefaultRouter() {

  }

  /**
   * Constructor.
   */
  public DefaultRouter(SipStack sipStack, String defaultRoute) {
    this.sipStack = (SipStackImpl) sipStack;
    if (defaultRoute != null) {
      try {
        this.defaultRoute = (Hop) this.sipStack.getAddressResolver()
            .resolveAddress((Hop) (new HopImpl(defaultRoute)));
      } catch (IllegalArgumentException ex) {
        // The outbound proxy is optional. If specified it should be host:port/transport.
        ((SIPTransactionStack) sipStack)
            .getLogWriter()
            .logError(
                "Invalid default route specification - need host:port/transport");
        throw ex;
      }
    }
  }

  /**
   * Return addresses for default proxy to forward the request to. The list is
   * organized in the following priority. If the requestURI refers directly to
   * a host, the host and port information are extracted from it and made the
   * next hop on the list. If the default route has been specified, then it is
   * used to construct the next element of the list. <code>
   * RouteHeader firstRoute = (RouteHeader) req.getHeader( RouteHeader.NAME );
   * if (firstRoute!=null) {
   *   URI uri = firstRoute.getAddress().getURI();
   *    if (uri.isSIPUri()) {
   *       SipURI nextHop = (SipURI) uri;
   *       if ( nextHop.hasLrParam() ) {
   *           // OK, use it
   *       } else {
   *           nextHop = fixStrictRouting( req );        <--- Here, make the modifications as per RFC3261
   *       }
   *   } else {
   *       // error: non-SIP URI not allowed in Route headers
   *       throw new SipException( "Request has Route header with non-SIP URI" );
   *   }
   * } else if (outboundProxy!=null) {
   *   // use outbound proxy for nextHop
   * } else if ( req.getRequestURI().isSipURI() ) {
   *   // use request URI for nextHop
   * }
   *
   * </code>
   *
   * @param request
   *            is the sip request to route.
   *
   */
  public Hop getNextHop(Request request) throws SipException {

    SIPRequest sipRequest = (SIPRequest) request;

    RequestLine requestLine = sipRequest.getRequestLine();
    if (requestLine == null) {
      return defaultRoute;
    }
    javax.sip.address.URI requestURI = requestLine.getUri();
    if (requestURI == null)
      throw new IllegalArgumentException("Bad message: Null requestURI");

    RouteList routes = sipRequest.getRouteHeaders();

    /*
     * In case the topmost Route header contains no 'lr' parameter (which
     * means the next hop is a strict router), the implementation will
     * perform 'Route Information Postprocessing' as described in RFC3261
     * section 16.6 step 6 (also known as "Route header popping"). That is,
     * the following modifications will be made to the request:
     *
     * The implementation places the Request-URI into the Route header field
     * as the last value.
     *
     * The implementation then places the first Route header field value
     * into the Request-URI and removes that value from the Route header
     * field.
     *
     * Subsequently, the request URI will be used as next hop target
     */

    if (routes != null) {

      // to send the request through a specified hop the application is
      // supposed to prepend the appropriate Route header which.
      Route route = (Route) routes.getFirst();
      URI uri = route.getAddress().getURI();
      if (uri.isSipURI()) {
        SipURI sipUri = (SipURI) uri;
        if (!sipUri.hasLrParam()) {

          fixStrictRouting(sipRequest);
          if (sipStack.isLoggingEnabled())
            sipStack.logWriter
                .logDebug("Route post processing fixed strict routing");
        }

        Hop hop = createHop(sipUri,request);
        if (sipStack.isLoggingEnabled())
          sipStack.logWriter
              .logDebug("NextHop based on Route:" + hop);
        return hop;
      } else {
        throw new SipException("First Route not a SIP URI");
      }

    } else if (requestURI.isSipURI()
        && ((SipURI) requestURI).getMAddrParam() != null) {
      Hop hop = createHop((SipURI) requestURI,request);
      if (sipStack.isLoggingEnabled())
        sipStack.logWriter
            .logDebug("Using request URI maddr to route the request = "
                + hop.toString());
      ((SipURI) requestURI).removeParameter("maddr");
           
           
      return hop;

    } else if (defaultRoute != null) {
      if (sipStack.isLoggingEnabled())
        sipStack.logWriter
            .logDebug("Using outbound proxy to route the request = "
                + defaultRoute.toString());
      return defaultRoute;
    } else if (requestURI.isSipURI()) {
      Hop hop = createHop((SipURI) requestURI,request);
      if (hop != null && sipStack.isLoggingEnabled())
        sipStack.logWriter.logDebug("Used request-URI for nextHop = "
            + hop.toString());
      else if (sipStack.isLoggingEnabled()) {
        sipStack.logWriter
            .logDebug("returning null hop -- loop detected");
      }
      return hop;

    } else {
      // The internal router should never be consulted for non-sip URIs.
      InternalErrorHandler.handleException("Unexpected non-sip URI",
          this.sipStack.logWriter);
      return null;
    }

  }

  /**
   * Performs strict router fix according to RFC3261 section 16.6 step 6
   *
   * pre: top route header in request has no 'lr' parameter in URI post:
   * request-URI added as last route header, new req-URI = top-route-URI
   */
  public void fixStrictRouting(SIPRequest req) {

    RouteList routes = req.getRouteHeaders();
    Route first = (Route) routes.getFirst();
    SipUri firstUri = (SipUri) first.getAddress().getURI();
    routes.removeFirst();

    // Add request-URI as last Route entry
    AddressImpl addr = new AddressImpl();
    addr.setAddess(req.getRequestURI()); // don't clone it
    Route route = new Route(addr);

    routes.add(route); // as last one
    req.setRequestURI(firstUri);
    if (sipStack.getLogWriter().isLoggingEnabled()) {
      sipStack.getLogWriter().logDebug("post: fixStrictRouting" + req);
    }
  }

  /**
   * Utility method to create a hop from a SIP URI
   *
   * @param sipUri
   * @return
   */
 

  private final Hop createHop(SipURI sipUri, Request request) {
    // always use TLS when secure
    String transport = sipUri.isSecure() ? SIPConstants.TLS : sipUri
        .getTransportParam();
    if (transport == null) {
      //@see issue 131
      ViaHeader via = (ViaHeader) request.getHeader(ViaHeader.NAME);
      transport = via.getTransport();
    }
   
    // sipUri.removeParameter("transport");

    int port;
    if (sipUri.getPort() != -1) {
      port = sipUri.getPort();
    } else {
      if (transport.equalsIgnoreCase(SIPConstants.TLS))
        port = 5061;
      else
        port = 5060; // TCP or UDP
    }
    String host = sipUri.getMAddrParam() != null ? sipUri.getMAddrParam()
        : sipUri.getHost();
    AddressResolver addressResolver = this.sipStack.getAddressResolver();
    return addressResolver
        .resolveAddress(new HopImpl(host, port, transport));

  }

  /**
   * Get the default hop.
   *
   * @return defaultRoute is the default route. public java.util.Iterator
   *         getDefaultRoute(Request request) { return
   *         this.getNextHops((SIPRequest)request); }
   */

  public javax.sip.address.Hop getOutboundProxy() {
    return this.defaultRoute;
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.sip.address.Router#getNextHop(javax.sip.message.Request)
   */
  public ListIterator getNextHops(Request request) {
    try {
      LinkedList llist = new LinkedList();
      llist.add(this.getNextHop(request));
      return llist.listIterator();
    } catch (SipException ex) {
      return null;
    }

  }
}
TOP

Related Classes of gov.nist.javax.sip.stack.DefaultRouter

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.