/* * 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. * *
* When javax.sip.USE_ROUTER_FOR_ALL_URIS
is set to
* false
, the next hop is determined according to the following
* algorithm:
*
javax.sip.OUTBOUND_PROXY
is set,
* use its value as the next hop
* * (*)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: *
* 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
* }
*
*
*
* @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.getStackLogger()
.logDebug("Route post processing fixed strict routing");
}
Hop hop = createHop(sipUri,request);
if (sipStack.isLoggingEnabled())
sipStack.getStackLogger()
.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.getStackLogger()
.logDebug("Using request URI maddr to route the request = "
+ hop.toString());
// JvB: don't remove it!
// ((SipURI) requestURI).removeParameter("maddr");
return hop;
} else if (defaultRoute != null) {
if (sipStack.isLoggingEnabled())
sipStack.getStackLogger()
.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.getStackLogger().logDebug("Used request-URI for nextHop = "
+ hop.toString());
else if (sipStack.isLoggingEnabled()) {
sipStack.getStackLogger()
.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.getStackLogger());
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.isLoggingEnabled()) {
sipStack.getStackLogger().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;
}
}
}