1600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/*
2600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Conditions Of Use
3600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
4600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * This software was developed by employees of the National Institute of
5600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Standards and Technology (NIST), an agency of the Federal Government.
6600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Pursuant to title 15 Untied States Code Section 105, works of NIST
7600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * employees are not subject to copyright protection in the United States
8600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * and are considered to be in the public domain.  As a result, a formal
9600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * license is not needed to use the software.
10600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
11600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * This software is provided by NIST as a service and is expressly
12600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * provided "AS IS."  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
13600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
14600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
15600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * AND DATA ACCURACY.  NIST does not warrant or make any representations
16600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * regarding the use of the software or the results thereof, including but
17600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * not limited to the correctness, accuracy, reliability or usefulness of
18600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * the software.
19600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
20600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Permission to use this software is contingent upon your acceptance
21600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * of the terms of this agreement
22600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
23600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * .
24600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
25600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */
26600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/*******************************************************************************
27600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).       *
28600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang ******************************************************************************/
29600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangpackage gov.nist.javax.sip.stack;
30600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
31600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.message.*;
32600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.address.*;
33600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.*;
34600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.*;
35600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.core.*;
36600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.core.net.AddressResolver;
37600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
38600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.*;
39600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.util.Iterator;
40600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.util.LinkedList;
41600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.util.ListIterator;
42600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
43600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.header.RouteHeader;
44600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.header.ViaHeader;
45600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.message.*;
46600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.address.*;
47600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
48600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/*
49600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Bug reported by Will Scullin -- maddr was being ignored when routing
50600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * requests. Bug reported by Antonis Karydas - the RequestURI can be a non-sip
51600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * URI Jiang He - use address in route header. Significant changes to conform to
52600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * RFC 3261 made by Jeroen van Bemmel. Hagai Sela contributed a bug fix to the
53600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * strict route post processing code.
54600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
55600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */
56600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
57600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/**
58600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * This is the default router. When the implementation wants to forward a
59600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * request and had run out of othe options, then it calls this method to figure
60600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * out where to send the request. The default router implements a simple
61600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * "default routing algorithm" which just forwards to the configured proxy
62600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * address.
63600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
64600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * <p>
65600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * When <code>javax.sip.USE_ROUTER_FOR_ALL_URIS</code> is set to
66600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * <code>false</code>, the next hop is determined according to the following
67600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * algorithm:
68600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * <ul>
69600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * <li> If the request contains one or more Route headers, use the URI of the
70600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * topmost Route header as next hop, possibly modifying the request in the
71600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * process if the topmost Route header contains no lr parameter(*)
72600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * <li> Else, if the property <code>javax.sip.OUTBOUND_PROXY</code> is set,
73600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * use its value as the next hop
74600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * <li> Otherwise, use the request URI as next hop. If the request URI is not a
75600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * SIP URI, call {@link javax.sip.address.Router#getNextHop(Request)} provided
76600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * by the application.
77600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * </ul>
78600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
79600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * <p>
80600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * (*)Note that in case the topmost Route header contains no 'lr' parameter
81600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * (which means the next hop is a strict router), the implementation will
82600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * perform 'Route Information Postprocessing' as described in RFC3261 section
83600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 16.6 step 6 (also known as "Route header popping"). That is, the following
84600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * modifications will be made to the request:
85600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * <ol>
86600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * <li>The implementation places the Request-URI into the Route header field as
87600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * the last value.
88600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * <li>The implementation then places the first Route header field value into
89600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * the Request-URI and removes that value from the Route header field.
90600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * </ol>
91600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Subsequently, the request URI will be used as next hop target
92600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
93600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
94600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @version 1.2 $Revision: 1.17 $ $Date: 2009/11/14 20:06:17 $
95600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
96600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @author M. Ranganathan <br/>
97600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
98600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */
99600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangpublic class DefaultRouter implements Router {
100600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
101600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private SipStackImpl sipStack;
102600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
103600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private Hop defaultRoute;
104600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
105600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private DefaultRouter() {
106600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
107600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
108600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
109600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
110600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Constructor.
111600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
112600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public DefaultRouter(SipStack sipStack, String defaultRoute) {
113600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.sipStack = (SipStackImpl) sipStack;
114600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (defaultRoute != null) {
115600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            try {
116600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                this.defaultRoute = (Hop) this.sipStack.getAddressResolver()
117600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        .resolveAddress((Hop) (new HopImpl(defaultRoute)));
118600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } catch (IllegalArgumentException ex) {
119600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // The outbound proxy is optional. If specified it should be host:port/transport.
120600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                ((SIPTransactionStack) sipStack)
121600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        .getStackLogger()
122600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        .logError(
123600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                "Invalid default route specification - need host:port/transport");
124600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                throw ex;
125600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
126600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
127600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
128600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
129600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
130600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Return addresses for default proxy to forward the request to. The list is
131600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * organized in the following priority. If the requestURI refers directly to
132600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * a host, the host and port information are extracted from it and made the
133600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * next hop on the list. If the default route has been specified, then it is
134600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * used to construct the next element of the list. <code>
135600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * RouteHeader firstRoute = (RouteHeader) req.getHeader( RouteHeader.NAME );
136600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * if (firstRoute!=null) {
137600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *   URI uri = firstRoute.getAddress().getURI();
138600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *    if (uri.isSIPUri()) {
139600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *       SipURI nextHop = (SipURI) uri;
140600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *       if ( nextHop.hasLrParam() ) {
141600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *           // OK, use it
142600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *       } else {
143600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *           nextHop = fixStrictRouting( req );        <--- Here, make the modifications as per RFC3261
144600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *       }
145600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *   } else {
146600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *       // error: non-SIP URI not allowed in Route headers
147600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *       throw new SipException( "Request has Route header with non-SIP URI" );
148600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *   }
149600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * } else if (outboundProxy!=null) {
150600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *   // use outbound proxy for nextHop
151600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * } else if ( req.getRequestURI().isSipURI() ) {
152600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *   // use request URI for nextHop
153600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * }
154600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
155600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * </code>
156600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
157600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param request
158600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *            is the sip request to route.
159600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
160600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
161600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public Hop getNextHop(Request request) throws SipException {
162600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
163600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        SIPRequest sipRequest = (SIPRequest) request;
164600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
165600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        RequestLine requestLine = sipRequest.getRequestLine();
166600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (requestLine == null) {
167600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return defaultRoute;
168600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
169600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        javax.sip.address.URI requestURI = requestLine.getUri();
170600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (requestURI == null)
171600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw new IllegalArgumentException("Bad message: Null requestURI");
172600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
173600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        RouteList routes = sipRequest.getRouteHeaders();
174600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
175600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        /*
176600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * In case the topmost Route header contains no 'lr' parameter (which
177600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * means the next hop is a strict router), the implementation will
178600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * perform 'Route Information Postprocessing' as described in RFC3261
179600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * section 16.6 step 6 (also known as "Route header popping"). That is,
180600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * the following modifications will be made to the request:
181600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         *
182600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * The implementation places the Request-URI into the Route header field
183600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * as the last value.
184600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         *
185600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * The implementation then places the first Route header field value
186600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * into the Request-URI and removes that value from the Route header
187600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * field.
188600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         *
189600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * Subsequently, the request URI will be used as next hop target
190600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         */
191600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
192600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (routes != null) {
193600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
194600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // to send the request through a specified hop the application is
195600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // supposed to prepend the appropriate Route header which.
196600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            Route route = (Route) routes.getFirst();
197600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            URI uri = route.getAddress().getURI();
198600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (uri.isSipURI()) {
199600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                SipURI sipUri = (SipURI) uri;
200600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (!sipUri.hasLrParam()) {
201600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
202600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    fixStrictRouting(sipRequest);
203600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (sipStack.isLoggingEnabled())
204600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        sipStack.getStackLogger()
205600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                .logDebug("Route post processing fixed strict routing");
206600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
207600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
208600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                Hop hop = createHop(sipUri,request);
209600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (sipStack.isLoggingEnabled())
210600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    sipStack.getStackLogger()
211600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            .logDebug("NextHop based on Route:" + hop);
212600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                return hop;
213600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } else {
214600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                throw new SipException("First Route not a SIP URI");
215600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
216600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
217600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else if (requestURI.isSipURI()
218600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                && ((SipURI) requestURI).getMAddrParam() != null) {
219600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            Hop hop = createHop((SipURI) requestURI,request);
220600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (sipStack.isLoggingEnabled())
221600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                sipStack.getStackLogger()
222600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        .logDebug("Using request URI maddr to route the request = "
223600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                + hop.toString());
224600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
225600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // JvB: don't remove it!
226600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // ((SipURI) requestURI).removeParameter("maddr");
227600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
228600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return hop;
229600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
230600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else if (defaultRoute != null) {
231600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (sipStack.isLoggingEnabled())
232600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                sipStack.getStackLogger()
233600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        .logDebug("Using outbound proxy to route the request = "
234600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                + defaultRoute.toString());
235600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return defaultRoute;
236600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else if (requestURI.isSipURI()) {
237600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            Hop hop = createHop((SipURI) requestURI,request);
238600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (hop != null && sipStack.isLoggingEnabled())
239600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                sipStack.getStackLogger().logDebug("Used request-URI for nextHop = "
240600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + hop.toString());
241600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            else if (sipStack.isLoggingEnabled()) {
242600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                sipStack.getStackLogger()
243600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        .logDebug("returning null hop -- loop detected");
244600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
245600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return hop;
246600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
247600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else {
248600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // The internal router should never be consulted for non-sip URIs.
249600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            InternalErrorHandler.handleException("Unexpected non-sip URI",
250600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    this.sipStack.getStackLogger());
251600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return null;
252600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
253600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
254600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
255600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
256600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
257600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Performs strict router fix according to RFC3261 section 16.6 step 6
258600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
259600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * pre: top route header in request has no 'lr' parameter in URI post:
260600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * request-URI added as last route header, new req-URI = top-route-URI
261600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
262600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void fixStrictRouting(SIPRequest req) {
263600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
264600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        RouteList routes = req.getRouteHeaders();
265600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        Route first = (Route) routes.getFirst();
266600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        SipUri firstUri = (SipUri) first.getAddress().getURI();
267600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        routes.removeFirst();
268600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
269600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Add request-URI as last Route entry
270600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        AddressImpl addr = new AddressImpl();
271600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        addr.setAddess(req.getRequestURI()); // don't clone it
272600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        Route route = new Route(addr);
273600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
274600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        routes.add(route); // as last one
275600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        req.setRequestURI(firstUri);
276600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (sipStack.isLoggingEnabled()) {
277600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            sipStack.getStackLogger().logDebug("post: fixStrictRouting" + req);
278600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
279600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
280600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
281600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
282600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Utility method to create a hop from a SIP URI
283600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
284600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param sipUri
285600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return
286600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
287600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
288600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
289600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private final Hop createHop(SipURI sipUri, Request request) {
290600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // always use TLS when secure
291600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String transport = sipUri.isSecure() ? SIPConstants.TLS : sipUri
292600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                .getTransportParam();
293600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (transport == null) {
294600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            //@see issue 131
295600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            ViaHeader via = (ViaHeader) request.getHeader(ViaHeader.NAME);
296600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            transport = via.getTransport();
297600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
298600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
299600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // sipUri.removeParameter("transport");
300600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
301600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        int port;
302600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (sipUri.getPort() != -1) {
303600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            port = sipUri.getPort();
304600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else {
305600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (transport.equalsIgnoreCase(SIPConstants.TLS))
306600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                port = 5061;
307600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            else
308600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                port = 5060; // TCP or UDP
309600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
310600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String host = sipUri.getMAddrParam() != null ? sipUri.getMAddrParam()
311600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                : sipUri.getHost();
312600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        AddressResolver addressResolver = this.sipStack.getAddressResolver();
313600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return addressResolver
314600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                .resolveAddress(new HopImpl(host, port, transport));
315600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
316600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
317600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
318600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
319600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get the default hop.
320600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
321600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return defaultRoute is the default route. public java.util.Iterator
322600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *         getDefaultRoute(Request request) { return
323600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *         this.getNextHops((SIPRequest)request); }
324600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
325600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
326600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public javax.sip.address.Hop getOutboundProxy() {
327600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return this.defaultRoute;
328600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
329600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
330600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
331600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * (non-Javadoc)
332600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
333600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @see javax.sip.address.Router#getNextHop(javax.sip.message.Request)
334600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
335600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public ListIterator getNextHops(Request request) {
336600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        try {
337600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            LinkedList llist = new LinkedList();
338600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            llist.add(this.getNextHop(request));
339600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return llist.listIterator();
340600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } catch (SipException ex) {
341600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return null;
342600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
343600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
344600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
345600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang}
346