/** * Creates a client transaction to handle a new request. Gets the real message channel from the * superclass, and then creates a new client transaction wrapped around this channel. * * @param nextHop Hop to create a channel to contact. */ public MessageChannel createMessageChannel(int sourcePort, Hop nextHop) throws UnknownHostException { synchronized (clientTransactions) { // New client transaction to return SIPTransaction returnChannel; // Create a new client transaction around the // superclass' message channel MessageChannel mc = super.createMessageChannel(sourcePort, nextHop); // Superclass will return null if no message processor // available for the transport. if (mc == null) return null; returnChannel = createClientTransaction(mc); clientTransactions.add(0, (SIPClientTransaction) returnChannel); ((SIPClientTransaction) returnChannel).setViaPort(nextHop.getPort()); ((SIPClientTransaction) returnChannel).setViaHost(nextHop.getHost()); // Add the transaction timer for the state machine. returnChannel.startTransactionTimer(); return returnChannel; } }
/** * 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.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; } }