/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
* Copyright (c) Ericsson AB, 2004-2008. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can obtain
* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package com.ericsson.ssa.sip;
import com.ericsson.ssa.config.LayerHandler;
import com.ericsson.ssa.config.SipRequestDispatcher;
import com.ericsson.ssa.container.sim.ArInfo;
import static com.ericsson.ssa.sip.Header.P_ASSERTED_ID;
import static com.ericsson.ssa.sip.Header.P_PREFERRED_ID;
import com.ericsson.ssa.sip.PathNode.Type;
import com.ericsson.ssa.sip.dns.TargetTuple;
import com.ericsson.ssa.sip.transaction.ClientTransactionRegistrationListener;
import com.ericsson.ssa.sip.transaction.TransactionManager;
import org.jvnet.glassfish.comms.deployment.backend.SessionCase;
import org.jvnet.glassfish.comms.security.auth.impl.AuthInfoImpl;
import org.jvnet.glassfish.comms.security.auth.impl.ClientDigestCreator;
import org.jvnet.glassfish.comms.security.auth.impl.PAssertedAuthenticator;
import org.jvnet.glassfish.comms.security.auth.impl.PAssertedAuthenticatorFactory;
import org.jvnet.glassfish.comms.util.SipServletRequestFacade;
import java.io.BufferedReader;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletInputStream;
import javax.servlet.sip.Address;
import javax.servlet.sip.AuthInfo;
import javax.servlet.sip.B2buaHelper;
import javax.servlet.sip.Proxy;
import javax.servlet.sip.ServletParseException;
import javax.servlet.sip.SipServletRequest;
import javax.servlet.sip.SipServletResponse;
import javax.servlet.sip.SipURI;
import javax.servlet.sip.TooManyHopsException;
import javax.servlet.sip.UAMode;
import javax.servlet.sip.URI;
import javax.servlet.sip.ar.SipApplicationRoutingDirective;
import javax.servlet.sip.ar.SipApplicationRoutingRegion;
/**
* @author ekrigro
* @reviewed ejoelbi 2006-oct-19
*/
public class SipServletRequestImpl extends SipServletMessageImpl
implements SipServletRequest, SipServletRequestFacade, Externalizable {
/**
* Comment for <code>serialVersionUID</code>
*/
public static final String CLIENT_CERT = "javax.servlet.request.X509Certificate";
private static final long serialVersionUID = 3257849874501548343L;
private static final Set<String> _disallowedRecordRouteURIParams = new HashSet<String>();
public static final List<String> NON_INITIAL_REQUEST_METHODS = Arrays.asList(new String[] {
"CANCEL", "BYE", "PRACK", "ACK", "UPDATE", "INFO"
});
private static int debugResponse = -1;
static {
_disallowedRecordRouteURIParams.add("transport");
_disallowedRecordRouteURIParams.add("lr");
_disallowedRecordRouteURIParams.add("ttl");
_disallowedRecordRouteURIParams.add("user");
_disallowedRecordRouteURIParams.add("method");
_disallowedRecordRouteURIParams.add("maddr");
String s = System.getProperty("org.glassfish.sip.debugResponse");
if (s != null) {
s = s.trim();
if (s.equals("*")) {
debugResponse = 0;
} else if (!s.equals("")){
try {
debugResponse = Integer.parseInt(s);
} catch (Exception e) {
}
}
}
}
private static final Logger _logger = (Logger) Logger.getLogger(
"SipContainer");
private URI _requestURI;
private boolean _isInitial = false;
private ProxyContext _proxyContext = null;
private boolean m_IsInPath = false;
private SessionCase m_SessionCase = SessionCase.INTERNAL;
private SipServletRequestImpl _transactionRequest = null;
protected boolean _IsRecordRouteIndicated = false;
protected boolean _IsPathIndicated = false;
private volatile int _sentResponseCode = -1;
private volatile boolean finalResponseGenerated = false;
private int _rseq = 0;
protected List<Dispatcher> _retransmission_applicationStack = null;
private Address _poppedRoute = null;
private volatile Address _initialPoppedRoute = null;
private ArInfo _arInfo = new ArInfo(null, null);
private SipServletRequestImpl _linkedRequest = null;
private B2buaHelper _b2buahelper = null;
private boolean _supervised = true;
private Map<String, String> _recordRouteURIParams = new HashMap<String, String>(8);
private Map<String, String> _pathURIParams = new HashMap<String, String>(8);
private Map<String, String> _requestParams = new HashMap<String, String>(8);
private boolean requestSent = false;
private SipApplicationRoutingDirective _directive = SipApplicationRoutingDirective.NEW;
private String transactionId;
private volatile int timerC;
private volatile boolean isFirstInvocation = true;
private volatile boolean isRoutingDirectiveExplicitlySet = false;
private transient SessionTarget st;
// isNoCancel should not be copied in clone
private volatile boolean isNoCancel = false;
private String authInfoHeader = null;
private int responseStatusCode = -1;
private URI _subscriberURI;
private List<Address> pushedRoutes = null;
/**
* Listener that gets callback if request is registered with ClientTransaction
*
*/
private ClientTransactionRegistrationListener clientTransactionRegistrationListener =
null;
// not need for synchronisation since a single thread will modify the list
private transient List<TargetTuple> _failedTargets = new ArrayList<TargetTuple>();
public SipServletRequestImpl() {
super();
_messageType = SipMessageType.SipRequest;
}
public SipServletRequestImpl(String method, URI requestURI, String protocol) {
super(method, protocol);
_requestURI = requestURI;
_messageType = SipMessageType.SipRequest;
}
public boolean isNoCancel() {
return isNoCancel;
}
public void setNoCancel() {
isNoCancel = true;
}
public URI getRequestURI() {
return _requestURI;
}
protected void addAuthInfoHeader(SipServletResponse response) {
if (authInfoHeader != null) {
response.addHeader(Header.AUTHENTICATION_INFO, authInfoHeader);
this.authInfoHeader = null; //reset after being used.
}
}
protected void setAuthInfoHeader(String value) {
this.authInfoHeader = value;
}
public boolean isFirstInvocation() {
return isFirstInvocation;
}
public void setFirstInvocation(boolean value) {
isFirstInvocation = value;
}
/**
* Returns that a Record Route header should be added to this response
*
* @return whether a Record Route header should be added
*/
public boolean isRecordRouteIndicated() {
return _IsRecordRouteIndicated;
}
/**
* States that a Record Route header should be added to this response
*/
public void indicateRecordRoute() {
_IsRecordRouteIndicated = true;
}
/**
* Set by the proxy branch to save the routes pushed to this request by AR
*/
public void setPushedRouteList(List<Address> list) {
this.pushedRoutes = list;
}
/**
* return the pushed route list to proxy branch.
*/
public List<Address> getPushedRouteList() {
return this.pushedRoutes;
}
/**
* Returns that a Path header should be added to this response
*
* @return whether a Path header should be added
*/
public boolean isPathIndicated() {
return _IsPathIndicated;
}
/**
* States that a Path header should be added to this response
*/
public void indicatePath() {
_IsPathIndicated = true;
}
public void setRequestURI(URI requestURI) {
if (requestURI == null) {
throw new NullPointerException(
"Not allowed to set null request URI");
}
_requestURI = requestURI;
}
// TEST for user centric
public void writeExternal(ObjectOutput output) throws IOException {
try {
// Write the req uri
output.writeObject(_requestURI); // TODO check write External on URI
// classes
// Let the Message class handle it's properties
super.writeExternal(output);
} catch (Exception ignore) {
}
}
public void readExternal(ObjectInput input) throws IOException {
try {
_requestURI = (URI) input.readObject();
super.readExternal(input);
} catch (Exception ignore) {
}
}
public Type isDirection() {
if (isInitial()) {
_Type = Type.Caller;
return _Type;
}
return super.isDirection();
}
public void pushRoute(SipURI route) {
Address routeAddress = _sf.createAddress(route);
pushRoute(routeAddress);
}
public void pushRoute(Address routeAddress) {
if (!isPushRouteAllowed()) {
throw new IllegalStateException(
"It is no support to call pushRoute in this state.");
}
if (headerMap.containsKey(Header.ROUTE)) {
Header header = headerMap.get(Header.ROUTE);
header.setAddressValue(routeAddress, true);
} else {
Header header = Header.createFormatted(Header.ROUTE, this);
header.setAddressValue(routeAddress, true);
headerMap.put(Header.ROUTE, header);
}
if (this.pushedRoutes != null) {
this.pushedRoutes.add(routeAddress);
}
}
public void pushPath(Address pathAddress) {
if (!getMethod().equals("REGISTER")) {
throw new IllegalStateException(
"It's not allowed to call pushPath for non-REGISTER requests.");
}
//Verify that the REGISTER request has a Supported header containing path
boolean pathSupported = false;
ListIterator<String> supportedList = getHeaders(Header.SUPPORTED);
String supported = null;
while (supportedList.hasNext()) {
supported = (String) supportedList.next();
if (supported.equals("path")) {
pathSupported = true;
}
}
if (!pathSupported) {
throw new IllegalStateException(
"The REGISTER request is missing required option path in Supported header.");
}
if (headerMap.containsKey(Header.PATH)) {
Header header = headerMap.get(Header.PATH);
header.setAddressValue(pathAddress, true);
} else {
Header header = Header.createFormatted(Header.PATH, this);
header.setAddressValue(pathAddress, true);
headerMap.put(Header.PATH, header);
}
}
public int getMaxForwards() {
Header header = headerMap.get(Header.MAX_FORWARDS);
if (header == null) {
return -1;
}
String mf = header.getValue();
if (mf == null) {
return -1;
}
return Integer.parseInt(mf);
}
public void setMaxForwards(int nr) {
// TODO Could be optimized since no pretty print is required in this
// case
if ((nr >= 0) && (nr <= 255)) {
setPrettyHeader(Header.MAX_FORWARDS, String.valueOf(nr));
} else {
throw new IllegalArgumentException(
"Argument is out of 0 - 255 range");
}
}
public void setInitial(boolean isInitial) {
if (NON_INITIAL_REQUEST_METHODS.contains(getMethod())) {
// Ignore
return;
}
_isInitial = isInitial;
}
public boolean isInitial() {
return _isInitial;
}
public ServletInputStream getInputStream() throws IOException {
// TODO Auto-generated method stub
return null;
}
public BufferedReader getReader() throws IOException {
// TODO Auto-generated method stub
return null;
}
public void setInApplicationPath(boolean inPath) {
m_IsInPath = inPath;
}
public boolean isInApplicationPath() {
return m_IsInPath;
}
public ProxyContext getProxyContext() {
return _proxyContext;
}
public void setProxyContext(ProxyContext proxyContext) {
_proxyContext = proxyContext;
}
public Proxy getProxy() throws TooManyHopsException {
return getProxy(true);
}
public Proxy getProxy(boolean create) throws TooManyHopsException {
if (!isInitial()) {
throw new IllegalStateException("Applications should not attempt " +
"to explicitly proxy subsequent requests");
}
if (_b2buahelper != null) {
throw new IllegalStateException("Only allowed to be B2bua");
}
if (headerMap.get(Header.MAX_FORWARDS).getValue().equals("0")) {
throw new TooManyHopsException();
}
Proxy proxy = null;
if (getProxyContext() == null) {
if (isInApplicationPath()) {
// support of SSA1.1, 10.2.3 Sending Responses (as a Proxy),
// mandates to first fetch proxy before sending response
throw new IllegalStateException("Only allowed to be UA");
}
if (create) {
ProxyImpl proxyImpl = new ProxyImpl(getApplicationSessionImpl(),
this);
setProxyContext(new ProxyContext(proxyImpl, getSessionImpl()));
proxy = proxyImpl.getFacade(this);
}
} else {
proxy = getProxyContext().getProxy().getFacade(this);
}
return proxy;
}
public SipServletResponse createResponse(int code)
throws IllegalArgumentException, IllegalStateException {
checkResponseCode(code);
return createResponseImpl(code);
}
public SipServletResponseImpl createTerminatingResponse(int code) {
// Don't send a terminating response, if the request was an 'ACK',
// see TR HH52078
if (getMethod().equals("ACK")) {
return null;
}
SipServletResponseImpl resp = createResponseImpl(code);
if (!resp.hasToTag()) {
resp.createTag(Header.TO);
}
resp.setInitialRemote(getInitialRemote());
// Temp fix which sets the remote target to avoid nullpointer in
// NetworkManager
// TODO Investigate if we should add the ResolverManager to the
// transactionStack if
// a response needs to be sent on the way up in the stack from a layer
// below ResolverManager
// (when ResolverManager is not yet pushed on the transactionStack)
// If resolverManager is added it can handle reconnections through
// firewalls (received/rport param)
//
resp.setRemote(getRemote());
resp.setRequest(this); //To satisfy Proxy component if faled to send...
//TODO check if final proposal and why not in the createTerminatingResponse(int,String) method?
//Same for set remote!!! - Stoffe
return resp;
}
public SipServletResponseImpl create100TryingResponse() {
return createResponseImpl(100);
}
public SipServletResponseImpl createResponseImpl(int code) {
return populateResponse(new SipServletResponseImpl(this,
this.getProtocol(), code));
}
public SipServletResponse createResponse(int code, String phrase)
throws IllegalArgumentException, IllegalStateException {
checkResponseCode(code);
return createResponseImpl(code, phrase);
}
public SipServletResponseImpl createTerminatingResponse(int code,
String phrase) {
// Don't send a terminating response, if the request was an 'ACK',
// see TR HH52078
if (getMethod().equals("ACK")) {
return null;
}
SipServletResponseImpl resp = createResponseImpl(code, phrase);
if (!resp.hasToTag()) {
resp.createTag(Header.TO);
}
return resp;
}
public SipServletResponseImpl createResponseImpl(int code, String phrase) {
return populateResponse(new SipServletResponseImpl(this,
this.getProtocol(), code, phrase));
}
public SipServletRequest createCancel() {
return createCancelImpl();
}
public SipServletRequestImpl createCancelImpl()
throws IllegalStateException {
if (getMethod().equals("INVITE")) {
if ((responseStatusCode >= 200) && (getProxyContext() == null)) {
throw new IllegalStateException(
" Already received final response ");
}
Address fromCopy = (Address) ((AddressImpl) getFromImpl()).clone(true,
true);
Address toCopy = (Address) ((AddressImpl) getToImpl()).clone(true,
true);
SipServletRequestImpl req = new SipServletRequestImpl("CANCEL",
getRequestURI(), SipFactoryImpl.PROTOCOL_LINE);
// set To
Header toHeader = new SingleLineHeader(Header.TO, true);
toHeader.setAddressValue(toCopy, false);
req.setHeader(toHeader);
// set From
Header fromHeader = new SingleLineHeader(Header.FROM, true);
fromHeader.setAddressValue(fromCopy, false);
req.setHeader(fromHeader);
// set Max-Forwards
Header maxForwardsHeader = new SingleLineHeader(Header.MAX_FORWARDS,
false);
maxForwardsHeader.setValue("70", false);
req.setHeader(maxForwardsHeader);
// set CallID
Header callIDHeader = new SingleLineHeader(Header.CALL_ID, true);
callIDHeader.setValue(getCallId(), false);
req.setHeader(callIDHeader);
// set CSeq
Header cSeqHeader = new SingleLineHeader(Header.CSEQ, true);
cSeqHeader.setValue(Integer.toString(getCSeqNumber()) + " CANCEL",
false);
req.setHeader(cSeqHeader);
// copy ROUTE of INVITE...
Header route = getRawHeader(Header.ROUTE);
if (route != null) {
req.setHeader((Header) route.clone());
}
// update new request with session...
req.setSession(getSessionImpl());
// ...and dialog
req.setDialog(getDialog());
// find out direction
req.setDirection(isDirection());
// subsequent request
req.setInitial(false);
// Fetch the Application stack
List<Layer> layers = LayerHandler.getInstance().getLayers();
req._applicationStack.addAll(layers);
// The destination address, port, and transport for the CANCEL MUST
// be identical to those used to send the original request.
req.setRemote(getRemote());
copyNonSystemHeaders(req);
return req;
} else {
throw new IllegalStateException(
"Cancel is only allowed for INVITE.");
}
}
/**
* Copy all non-system headers from this message to the created request
* @param req The request to which the headers are added.
*/
protected void copyNonSystemHeaders(SipServletRequestImpl req) {
String headerName = null;
for(Iterator<String> headerNames = getHeaderNames() ; headerNames.hasNext();) {
headerName = headerNames.next();
if (headerName != null && ! Header.isSystemHeader(headerName, req)) {
Header header = getRawHeader(headerName);
if (header != null) {
req.setHeader((Header) header.clone());
}
}
}
}
public String getParameter(String name) {
return _requestParams.get(name);
}
public Enumeration getParameterNames() {
final Iterator<String> it = _requestParams.keySet().iterator();
return new Enumeration<String>() {
public boolean hasMoreElements() {
return it.hasNext();
}
public String nextElement() {
return it.next();
}
};
}
public String[] getParameterValues(String name) {
return new String[] { _requestParams.get(name) };
}
public Map getParameterMap() {
return Collections.unmodifiableMap(_requestParams);
}
public String getScheme() {
return _requestURI.getScheme();
}
public String getServerName() {
// Use information from getLocalAddr()....
return getLocalAddr();
}
public int getServerPort() {
// Use information from getLocalPort()....
return getLocalPort();
}
public String getRemoteHost() {
// Use information from getRemoteAddr()....
return getRemoteAddr();
}
/**
* Removes an attribute from the response.
* This method should be moved to SipServletMessageImpl when SipServletMessage
* is modified to contain the removeAttribute method.
*/
public void removeAttribute(String name) {
if (name == null) {
throw new NullPointerException();
}
if (attrib != null) {
attrib.remove(name);
}
}
public Locale getLocale() {
// Use information from getAcceptLanguage()....
return getAcceptLanguage();
}
public Enumeration<Locale> getLocales() {
// Use information from getAcceptLanguages()....
final Iterator<Locale> it = getAcceptLanguages();
return new Enumeration<Locale>() {
public boolean hasMoreElements() {
return it.hasNext();
}
public Locale nextElement() {
return it.next();
}
};
}
public RequestDispatcher getRequestDispatcher(String name) {
return new SipRequestDispatcher(name,
SipFactoryImpl.getInstance().getServiceHandler());
}
@Deprecated
public String getRealPath(String arg0) {
// Shall return null in a SIP context
return null;
}
public String getLocalName() {
// Use information from getLocalAddr()....
return getLocalAddr();
}
public String toString() {
StringBuilder sb = new StringBuilder(_method);
sb.append(' ');
sb.append(_requestURI);
sb.append(' ');
sb.append(SipFactoryImpl.PROTOCOL_LINE);
sb.append(SipFactoryImpl.NEW_LINE);
byte[] content = null;
try {
content = getRawContent();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
HashMap<String, Header> clonedHeaders = headerMap;
if (headerForm == HeaderForm.COMPACT) {
clonedHeaders = new HashMap<String, Header>(headerMap);
for (String s : Header.LONG_TO_SHORT_MAP.keySet()) {
if (clonedHeaders.containsKey(s)) {
Header h = clonedHeaders.get(s);
h.setName(Header.LONG_TO_SHORT_MAP.get(s));
}
}
}
Iterator<Header> i = clonedHeaders.values().iterator();
while (i.hasNext()) {
sb.append(i.next().toString());
}
sb.append(SipFactoryImpl.NEW_LINE);
if ((content != null) && (content.length > 0)) {
sb.append(new String(content));
}
return sb.toString();
}
//Returns the session target
public SessionTarget getSessionTarget() {
return this.st;
}
//Saves the Join/Replace SessionTarget handler
void setSessionTarget(SessionTarget st) {
this.st = st;
}
ByteBuffer toBufferFirstline(ByteBuffer bb)
throws UnsupportedEncodingException {
bb.put(_method.getBytes());
bb.put((byte) 0x20);
bb.put(_requestURI.toString().getBytes(SipFactoryImpl.SIP_CHARSET));
bb.put((byte) 0x20);
bb.put(SipFactoryImpl.PROTOCOL_LINE.getBytes());
bb.put(SipFactoryImpl.NEW_LINE.getBytes());
return bb;
}
public String toDebugString() {
StringBuilder sb = new StringBuilder(_method);
sb.append(" ");
sb.append(_requestURI);
sb.append(" ");
sb.append(super.toDebugString());
return sb.toString();
}
private SipServletResponseImpl populateResponse(
SipServletResponseImpl response) {
if (getMethod().equals("ACK")) {
throw new IllegalStateException("Not allowed to create response " +
response.getStatus() + " for ACK with callId = " + getCallId() +
", from = " + getFromImpl() + ", to = " + getToImpl());
}
int status = response.getStatus();
if (debugResponse == status || debugResponse == 0) {
_logger.warning("DEBUG CREATING RESPONSE for >> \n" + this);
_logger.warning("DEBUG RESPONSE >> \n" + response);
_logger.warning("DEBUG Thread dump follows >>");
Thread.dumpStack();
}
Iterator<Header> i = headerMap.values().iterator();
while (i.hasNext()) {
Header next = i.next();
if (next.equals(Header.VIA)) {
response.headerMap.put(Header.VIA, (Header) next.clone());
} else if (next.equals(Header.FROM)) {
response.headerMap.put(Header.FROM, (Header) next.clone());
} else if (next.equals(Header.TO)) {
response.headerMap.put(Header.TO, (Header) next.clone());
} // else if( next.equals( Header.P_ASSERTED_ID ) )
// response.headerMap.put( Header.P_ASSERTED_ID,
// (Header)next.clone()
// );
else if (next.equals(Header.CSEQ)) {
response.headerMap.put(Header.CSEQ, (Header) next.clone());
} else if (next.equals(Header.CALL_ID)) {
response.headerMap.put(Header.CALL_ID, (Header) next.clone());
} else if (next.equals(Header.RECORD_ROUTE)) {
response.headerMap.put(Header.RECORD_ROUTE,
(Header) next.clone());
} else if (next.equals(Header.EVENT)) {
if ("SUBSCRIBE".equals(_method)) {
response.headerMap.put(Header.EVENT, (Header) next.clone());
}
}
}
// Dialog must be set before setting Contact
response._dialog = _dialog;
response._method = _method;
response._transactionStack.addAll(_transactionStack);
response._sf = _sf;
response._local = _local;
// response._remote = _remote; ........ no longer do this, HF85359
response._session = _session;
response.setDirection(isDirection());
response.setBeKey(getBeKey());
// Set Version information in Server header
String version = System.getProperty("sip.module.version");
if (version != null) {
response.addHeader(Header.SERVER, version);
}
if (SipFactoryImpl.getContactRequirement(response) != HeaderRequirement.NOT_APPLICAPLE) {
//As per JSR 289 section 4.1.3
if (!SipFactoryImpl.contactAllowedFromServlet(response)) {
populateContactHeader(response);
}
}
// is this a feature of JSR 289 10.2.3 Sending Responses?
if (isInitial() && (getProxyContext() != null)) {
getProxyContext().getProxy().setVirtualProxyBranchRequest(response);
}
if (response.getStatus() >= 200) {
finalResponseGenerated = true;
}
return response;
}
public void populateContactHeader(SipServletResponseImpl response) {
dialogManager.addContact(response);
// Specific code for JSR116 TCK to reuse the transport in record-route/contact
// that a remote party sent, and include the same in the Contact header of the response.
if ("INVITE".equals(_method) || "REFER".equals(_method) ||
"SUBSCRIBE".equals(_method)) {
try {
// Check if Response has Record-Route headers
Address rrouteAddress = getAddressHeaderImpl(Header.RECORD_ROUTE);
SipURI sipuri = null;
if ((rrouteAddress != null) &&
rrouteAddress.getURI().isSipURI()) {
// 1. Use transport from top-most Record Route on the incoming Request
sipuri = (SipURI) rrouteAddress.getURI();
} else {
// 2. Use transport from Contact
URI remoteTarget = getAddressHeaderImpl("Contact").getURI();
if (remoteTarget.isSipURI()) {
sipuri = (SipURI) remoteTarget;
}
}
if ((sipuri != null) && (sipuri.getTransportParam() != null)) {
String transport = sipuri.getTransportParam();
Address contactAddress = response.getAddressHeaderImpl(Header.CONTACT);
if ((contactAddress != null) &&
contactAddress.getURI().isSipURI()) {
((SipURI) contactAddress.getURI()).setTransportParam(transport);
}
}
} catch (Exception e) {
// Should not happen, but consequences would be that the transport parameter is not set.
}
}
}
public void send() throws IOException {
validateMessageCommitted();
if (getInitialRemote() != null) {
throw new IllegalStateException("Incoming request cannot be send.");
}
DialogFragment p = getDialog();
PathNode uac = null;
//handleAssertedIdentity();
if (isInitial()) {
uac = new UA(getApplicationSessionImpl(), true);
// add to application path
p.addToPath(uac);
// need to add to transaction path
pushTransactionDispatcher(uac);
// when this thread returns it should not continue...
setSentOnThread(true);
} else {
// lets build the dispatcher list from the application path
Iterator<PathNode> iter = null;
if (isDirection() == Type.Caller) {
iter = p.getCallee2CallerPath();
} else if (isDirection() == Type.Callee) {
iter = p.getCaller2CalleePath();
} else {
throw new IOException("Don't know the direction of the flow.");
}
// add the dispatchers
while (iter.hasNext()) {
uac = iter.next();
SipSessionBase ss = uac.getSipSession();
if (ss != null && ss.isValid()) {
pushApplicationDispatcher(uac);
}
}
// last should not be stored because its the uac
popDispatcher();
// need to add to transaction path
pushTransactionDispatcher(uac);
}
uac.send(this);
requestSent = true;
}
public SessionCase getSessionCase() {
return m_SessionCase;
}
public void setSessionCase(SessionCase sessionCase) {
this.m_SessionCase = sessionCase;
}
public void removeSystemHeaders() {
// remove system headers
Iterator<String> i = Header.SYSTEM_HEADER_MAP.values().iterator();
while (i.hasNext()) {
headerMap.remove(i.next());
}
}
public void removeRemoteSettings() {
this._initialPoppedRoute = null;
this._initialRemote = null;
this._local = null;
}
public Object clone() {
SipServletRequestImpl clone = new SipServletRequestImpl(getMethod(),
getRequestURI(), getProtocol());
Iterator<Header> i = headerMap.values().iterator();
// deep copy
while (i.hasNext()) {
Header next = i.next();
clone.headerMap.put(next.getName(), (Header) next.clone());
}
clone.setUserPrincipal(this.getUserPrincipal());
clone.setUser(this.getRemoteUser());
// Fix for issue#955, application attributes shall not be cloned
// Note that when using SipRequestDispatcher.forward() the request
// is not cloned and thus the attributes are available for the servlet
// to which the request is forwarded.
if (systemAttrib != null) {
clone.systemAttrib = new HashMap<String, Object>(systemAttrib.size());
clone.systemAttrib.putAll(systemAttrib);
}
// shallow copy
clone.m_SessionCase = m_SessionCase;
clone._content_enc = _content_enc;
clone._content_byte = _content_byte;
clone._content_obj = _content_obj;
clone._roles = _roles;
clone._initialRemote = _initialRemote;
clone._remoteHop = _remoteHop;
clone._remote = _remote;
clone._local = _local;
clone._isInitial = _isInitial;
clone.isFirstInvocation = isFirstInvocation;
clone._session = _session;
clone._dialog = _dialog;
clone._sf = _sf;
clone._IsContactIndicated = _IsContactIndicated;
clone._IsPathIndicated = _IsPathIndicated;
clone._IsRecordRouteIndicated = _IsRecordRouteIndicated;
clone._headersComplete = _headersComplete;
clone._messageComplete = _messageComplete;
clone.m_IsInPath = m_IsInPath;
clone._rseq = _rseq;
clone._fragmentId = _fragmentId;
clone._supervised = _supervised;
clone._recordRouteURIParams = _recordRouteURIParams;
clone._pathURIParams = _pathURIParams;
clone._requestParams = _requestParams;
// JSR 289
clone._initialPoppedRoute = _initialPoppedRoute;
clone._poppedRoute = _poppedRoute;
clone._arInfo = _arInfo;
clone._directive = _directive;
clone.timerC = timerC;
clone.isRoutingDirectiveExplicitlySet = isRoutingDirectiveExplicitlySet;
clone.oi = oi;
clone._failedTargets = _failedTargets;
// find out direction
clone.setDirection(isDirection());
// copy transaction and application stacks
if (_transactionStack != null) {
clone._transactionStack.addAll(_transactionStack);
}
if (_applicationStack != null) {
clone._applicationStack.addAll(_applicationStack);
}
clone.setBeKey(getBeKey());
return clone;
}
public void saveRetransmissionApplicationStack() {
_retransmission_applicationStack = new ArrayList<Dispatcher>(_applicationStack);
}
public void restoreRetransmissionApplicationStack() {
// if null or empty...
if ((_applicationStack == null) ||
((_applicationStack != null) && _applicationStack.isEmpty())) {
_applicationStack = new ArrayList<Dispatcher>(_retransmission_applicationStack);
}
}
public Dispatcher popDispatcher() {
int size = _applicationStack.size();
if (size > 0) {
return _applicationStack.remove(size - 1);
}
return null;
}
public Dispatcher peekDispatcher() {
int size = _applicationStack.size();
if (size > 0) {
return _applicationStack.get(size - 1);
}
return null;
}
/**
* Returns the request that should be used by the response when internally
* traversing the path of the transaction or null if transaction path is
* empty.
*
* @return the request used by the response when traversing the transaction
* path
*/
public SipServletRequestImpl getTransactionRequest() {
return _transactionRequest;
}
/**
* Set the transaction request used by the response when travsersing the path
* of the transaction.
*
* @param request
* the request mapped to the response
*/
public void setTransactionRequest(SipServletRequestImpl request) {
_transactionRequest = request;
}
public void setFragmentId(String id) {
_fragmentId = id.toLowerCase();
}
/**
* This method will be called by the reponse object at send operation. Sets
* the indicator status code.
*
* @param status
* the indicator
*/
public void setSentResponse(int statusCode) {
_sentResponseCode = statusCode;
}
public boolean isSentResponse() {
return _sentResponseCode != -1;
}
public boolean isSentFinalResponse2xx() {
return (_sentResponseCode != -1) ? ((_sentResponseCode / 100) == 2)
: false;
}
void setResponseStatusCode(int code) {
responseStatusCode = code;
}
private boolean isValidStatusCode(int statusCode) {
if (_sentResponseCode != -1) {
if ((_sentResponseCode / 100) == 2) {
if (!allowMultiple2xx()) {
return false;
} else { // allow multiple 2xx
if ((statusCode / 100) != 2) {
// already sent 2xx final response,
// can't send non-2xx after...
return false;
}
// it's ok to send multiple 2xx with different to-tag
}
} else if ((_sentResponseCode / 100) > 2) {
// already sent non-2xx final response
return false;
}
}
return true;
}
private boolean allowMultiple2xx() {
return isB2buaHelper();
}
/*
* This method will check for: 1. If we have already sent a final response
* throw an IllegalStateException 2. If the status code out of range SIP
* codes throw an IllegalArgumentException
*/
private void checkResponseCode(int statusCode)
throws IllegalArgumentException, IllegalStateException {
if (!isValidStatusCode(statusCode)) {
throw new IllegalStateException(
"The request has already responded with a final response.");
}
if ((statusCode < 100) || (statusCode > 699)) {
throw new IllegalArgumentException("Invalid SIP status code.");
}
}
/**
* Will return true for an INVITE request which support 100rel extension in a
* Supported or Require header otherwise false.
*
* @return true for an INVITE request which support 100rel extension in a
* Supported or Require header otherwise false.
*/
public boolean is100RelSupportedOrRequire() {
if (getMethod().equals("INVITE")) {
ListIterator supportedList = getHeaders(Header.SUPPORTED);
String supported = null;
while (supportedList.hasNext()) {
supported = (String) supportedList.next();
if (supported.equals(SipFactoryImpl.SUPPORTED_100REL)) {
return true;
}
}
ListIterator requireList = getHeaders(Header.REQUIRE);
String require = null;
while (requireList.hasNext()) {
require = (String) requireList.next();
if (require.equals(SipFactoryImpl.SUPPORTED_100REL)) {
return true;
}
}
}
return false;
}
public int getAndIncrementRSeq() {
return ++_rseq;
}
public void setPoppedRoute(Address route) {
_poppedRoute = route;
}
public void setInitialPoppedRoute(Address a) {
_initialPoppedRoute = a;
_poppedRoute = a;
}
public Address getPoppedRoute() {
if (_poppedRoute == null) {
return null;
}
AddressImpl ai = (AddressImpl) _poppedRoute.clone();
if (ai != null) {
ai.setModifiable(isCommitted());
}
return ai;
}
public Address getInitialPoppedRoute() {
if (_initialPoppedRoute == null) {
return null;
}
AddressImpl ai = (AddressImpl) _initialPoppedRoute.clone();
if (ai != null) {
ai.setModifiable(isCommitted());
}
return ai;
}
public void setArInfo(ArInfo stateInfo) {
_arInfo = stateInfo;
}
public ArInfo getArInfo() {
return _arInfo;
}
public SipApplicationRoutingDirective getRoutingDirective()
throws IllegalStateException {
if (_isInitial) {
return _directive;
} else {
throw new IllegalStateException("Not an initial request");
}
}
public void setImplicitRoutingDirective(
SipApplicationRoutingDirective directive, SipServletRequest origRequest) {
if (!isRoutingDirectiveExplicitlySet) {
setInternalRoutingDirective(directive, origRequest);
} else {
// assumes the application knows what it is doing..
// TODO: this assumes once explcitly set never changed anymore
// is this really correct?
isRoutingDirectiveExplicitlySet = false;
// do not change it, the first time
}
}
public void setRoutingDirective(SipApplicationRoutingDirective directive,
SipServletRequest origRequest) throws IllegalStateException {
setInternalRoutingDirective(directive, origRequest);
isRoutingDirectiveExplicitlySet = true;
}
public void resetExplicit() {
isRoutingDirectiveExplicitlySet = false;
}
public void setInternalRoutingDirective(
SipApplicationRoutingDirective directive, SipServletRequest origRequest)
throws IllegalStateException {
// If directive is NEW, origRequest parameter is ignored.
if (SipApplicationRoutingDirective.NEW.equals(directive)) {
_directive = directive;
return;
}
// If directive if not NEW, we will try to copy the stateinfo from the
// original request that is being passed in. JSR289 gives some hints on
// how to do this, but it is not totally clear.
if (origRequest == null) {
// Just ignore it then, use whatever stateinfo we already have. For
// example, stateinfo may have been cloned when this request was
// constructed with the B2BUaHelper and some other original request.
_directive = directive;
return;
}
// JSR289 If directive is CONTINUE or REVERSE, the parameter origRequest
// must be an initial request dispatched by the container to this
// application, i.e. origRequest.isInitial() must be true.
if (SipApplicationRoutingDirective.CONTINUE.equals(directive) ||
SipApplicationRoutingDirective.REVERSE.equals(directive)) {
if (!origRequest.isInitial()) {
throw new IllegalStateException(
"You can only set a routing directive based on an initial" +
" request");
}
// This request must be a request created in a new SipSession or
// from an initial request, and must not have been sent.
if (!this._isInitial) {
throw new IllegalStateException(
"You cannot set a routing directive on a request that is" +
" not initial.");
}
if (requestSent) {
throw new IllegalStateException(
"You cannot set a routing directive on a request that has" +
" already been sent.");
}
// else set the directive and copy stateinfo
// -- TODO JSR289 is not clear on this --
this._directive = directive;
if (origRequest instanceof SipServletRequestImpl) {
this._arInfo = ((SipServletRequestImpl) origRequest).getArInfo();
} else {
_logger.warning(
"Could not copy state info (unknown type of origRequest)");
}
}
}
public SipServletRequestImpl getLinkedRequest() {
return _linkedRequest;
}
public void setLinkedRequest(SipServletRequestImpl linkedRequest) {
_linkedRequest = linkedRequest;
}
public B2buaHelper getB2buaHelper() {
if (_proxyContext != null) {
throw new IllegalStateException("Only allowed to be proxy");
}
if (_b2buahelper == null) {
_b2buahelper = new B2buaHelperImpl(this);
}
if (isInitial() && !isCommitted() && !getSessionImpl().isB2buaHelper()) {
// add this pending b2bua response
getSessionImpl().createPendingMessageHelper();
getSessionImpl().addPendingMessage(this, UAMode.UAS);
}
return _b2buahelper;
}
public void setB2buaHelper(B2buaHelper bua) {
_b2buahelper = bua;
}
public boolean isB2buaHelper() {
return _b2buahelper != null;
}
/**
* Gets the supervise state of this request.
* @return
*/
public boolean getSupervised() {
return _supervised;
}
/**
* Sets the supervised state of this request.
* @param supervised
*/
public void setSupervised(boolean supervised) {
_supervised = supervised;
}
public String getPathURIParam(String name) {
return _pathURIParams.get(name);
}
public Iterator getPathURIParamNames() {
return _pathURIParams.keySet().iterator();
}
public void removePathURIParam(String name) {
_pathURIParams.remove(name);
}
public void setPathURIParam(String name, String value) {
// Assume the same parameters are disallowed as for Record-Route
if (!_disallowedRecordRouteURIParams.contains(name)) {
_pathURIParams.put(name, value);
} else {
throw new IllegalArgumentException("Not allowed to set parameter '" +
name + "' on Path URI.");
}
}
public String getRecordRouteURIParam(String name) {
return _recordRouteURIParams.get(name);
}
public Iterator getRecordRouteURIParamNames() {
return _recordRouteURIParams.keySet().iterator();
}
public void removeRecordRouteURIParam(String name) {
_recordRouteURIParams.remove(name);
}
public void setRecordRouteURIParam(String name, String value) {
if (!_disallowedRecordRouteURIParams.contains(name)) {
_recordRouteURIParams.put(name, value);
} else {
throw new IllegalArgumentException("Not allowed to set parameter '" +
name + "' on Record-Route URI.");
}
}
/**
* Used on incoming requests to populate the parameters from the popped Route header
* @param uri the URI to extract parameters from
*/
public void setRecordRouteURI(URIImpl uri) {
Iterator<String> iter;
if (uri instanceof SipURIImpl) {
iter = ((SipURIImpl) uri).getParameterNames();
} else if (uri instanceof TelURLImpl) {
iter = ((TelURLImpl) uri).getParameterNames();
} else {
return;
}
while (iter.hasNext()) {
String name = iter.next();
String value = uri.getParameter(name);
if (!_disallowedRecordRouteURIParams.contains(name)) {
// Put parameters in _requestParams map
_requestParams.put(name, value);
}
}
}
/**
* Used on incoming requests to populate the parameters from the request URI
* @param uri the URI to extract parameters from
*/
public void setRequestParams(URIImpl uri) {
Iterator<String> iter;
if (uri instanceof SipURIImpl) {
iter = ((SipURIImpl) uri).getParameterNames();
} else if (uri instanceof TelURLImpl) {
iter = ((TelURLImpl) uri).getParameterNames();
} else {
return;
}
while (iter.hasNext()) {
String name = iter.next();
String value = uri.getParameter(name);
// Put parameters in _requestParams map
_requestParams.put(name, value);
}
}
@Override
public void setCertificate(X509Certificate[] cert) {
super.setCertificate(cert);
if (systemAttrib == null) {
systemAttrib = new HashMap<String, Object>(8);
}
this.systemAttrib.put(CLIENT_CERT, cert);
}
public void addAuthHeader(SipServletResponse response, AuthInfo info) {
if (response != null) {
ClientDigestCreator cdc = new ClientDigestCreator();
cdc.createDigest(info, this, response);
}
}
public void addAuthHeader(SipServletResponse response, String username,
String password) {
AuthInfo ai = new AuthInfoImpl();
Iterator<String> itr = response.getChallengeRealms();
while (itr.hasNext()) {
ai.addAuthInfo(response.getStatus(), itr.next(), username, password);
}
addAuthHeader(response, ai);
}
@Override
public boolean isCommitted() {
if (requestSent) {
return true;
}
if (finalResponseGenerated) {
return true;
}
if ((_sentResponseCode != -1) && ((_sentResponseCode / 100) > 1)) {
return true;
}
return false;
}
public void handleAssertedIdentity() {
ListIterator<String> passertedHeader = this.getHeaders(P_ASSERTED_ID);
ListIterator<String> ppreferredHeader = this.getHeaders(P_PREFERRED_ID);
if (passertedHeader.hasNext() || ppreferredHeader.hasNext()) {
PAssertedAuthenticator auth = (PAssertedAuthenticator) PAssertedAuthenticatorFactory.getInstance()
.getAuthenticator();
if (auth != null) {
TargetTuple remoteHost = ((SipServletRequestImpl) this).getRemote();
String host = "";
if (remoteHost != null) {
host = remoteHost.getIP();
}
auth.verifyMessage(this, host);
}
}
}
public String getTransactionId() {
if (getTransactionRequest() != null) {
return getTransactionRequest().getTransactionId();
} else {
return transactionId;
}
}
public void setTransactionId(String trId) {
this.transactionId = trId;
}
public void setTimerC(int seconds) {
this.timerC = seconds;
}
public int getTimerC() {
return timerC;
}
/**
* Pop the topmost Route header to simulate that request have exited and
* re-entered.
*
* @param req
* the request to manipulate
* @return true if route is popped, false otherwise
*/
public Address popRouteHeader() {
// loose route support: remove first route header
Address poppedRoute = null;
Header r = getRawHeader(Header.ROUTE);
if (r != null) {
r.setReadOnly(false);
ListIterator<Address> it_a = null;
try {
it_a = r.getAddressValues();
Address a = it_a.next();
URIImpl uri = (URIImpl) a.getURI();
if (uri.getLrParam()) {
if (_logger.isLoggable(Level.FINE)) {
_logger.log(Level.FINE, "Removing route = " + a);
}
it_a.remove();
// support of popped route added.
setRecordRouteURI(uri);
poppedRoute = a;
}
} catch (ServletParseException e) {
// Should not happen
}
r.setReadOnly(true);
}
return poppedRoute;
}
/**
* Examines the Route header of a request to determine if the request could
* stay inside the container
*
* @param req
* the request to examine
* @return true if route header exists and host part is "localhost" or
* "127.0.0.1", false otherwise
*/
public boolean isLocalRoute() {
// Check top Route header, if any
try {
AddressImpl route = (AddressImpl) getAddressHeaderImpl(Header.ROUTE);
if (route != null) {
return route.isLocal();
} else {
return false;
}
} catch (ServletParseException e) {
// Should never occur.
return false;
}
}
public SipApplicationRoutingRegion getRegion() {
if (_session != null) {
return _session.getRegion();
}
return null;
}
public URI getSubscriberURI() {
//What is directly set on request has
//the precedence.
if (_subscriberURI != null) {
return _subscriberURI;
} else if (_session != null) {
return _session.getSubscriberURI();
} else {
//should not happen.
return null;
}
}
public void setSubscriberURI(URI u) {
this._subscriberURI = u;
}
public void setRegion(SipApplicationRoutingRegion anRegion) {
if (_session != null) {
_session.setRegion(anRegion);
}
}
public ClientTransactionRegistrationListener getClientTransactionRegistrationListener() {
return clientTransactionRegistrationListener;
}
public void setClientTransactionRegistrationListener(
ClientTransactionRegistrationListener clientTransactionListener) {
this.clientTransactionRegistrationListener = clientTransactionListener;
}
/**
* This method makes sure that the contact header does not break the specs.
*
* @throws ServletParseException
*/
public void validateContact() throws ServletParseException
{
// 12.1.2 - If top route header or Request URI contains sips then
// contact must be sips (UAC behaviour). We also extend this check
// to take into account using sip uri scheme and transport=TLS.
Header contactHeader;
if (isContactIndicated() &&
(contactHeader = getRawHeader(Header.CONTACT)) != null)
{
boolean secure = useSecureContact();
AddressImpl contactAddress = (AddressImpl) contactHeader.getAddressValue();
if (contactAddress != null &&
contactAddress.getURI() != null &&
contactAddress.getURI().isSipURI())
{
SipURI contactUri = (SipURI) contactAddress.getURI();
contactUri.setPort(secure
? dialogManager.getVipSipsUri().getPort()
: dialogManager.getVipSipUri().getPort());
if (useSipsContact())
{
// Use SIPS URI scheme
contactUri.setSecure(true);
}
else
{
// Use SIP URI scheme
contactUri.setSecure(false);
if (secure)
{
contactUri.setTransportParam("tls");
}
}
}
}
}
/**
* Determines if the Contact header URI of a request sent
* as UAC must be secure or not. The meaning of secure in this case
* is defined by isUriSecure().
*
* @return True if and only if any route header is secure or the
* request URI is secure.
*/
private boolean useSecureContact()
{
return isRouteHeaderSecure() || isRequestUriSecure();
}
/**
* Determines if the Contact header URI of a request sent
* as UAC must use the SIPS URI scheme or not.
*
* @return True if and only if any route header is using SIPS or the
* request URI is using SIPS.
*/
private boolean useSipsContact()
{
return isRouteHeaderUsingSips() || isRequestUriUsingSips();
}
/**
* Returns true if the Route header is present and the URI in the Route header
* is secure according to isUriSecure().
*
* @return True if the Route header is present and the URI in the Route header
* is secure according to isUriSecure(), otherwise false.
*/
private boolean isRouteHeaderSecure()
{
Header r = getRawHeader(Header.ROUTE);
if (r != null)
{
try
{
if (r.getAddressValue() != null)
{
return isUriSecure(r.getAddressValue().getURI());
}
}
catch (ServletParseException ignore)
{
// Do nothing
}
}
return false;
}
/**
* Returns true if the Route header is present and the URI in the Route header
* is using SIPS URI scheme according to isUriUsingSips().
*
* @return True if the Route header is present and the URI in the Route header
* is using SIPS URI scheme according to isUriUsingSips(), otherwise false.
*/
private boolean isRouteHeaderUsingSips()
{
Header r = getRawHeader(Header.ROUTE);
if (r != null)
{
try
{
if (r.getAddressValue() != null)
{
return isUriUsingSips(r.getAddressValue().getURI());
}
}
catch (ServletParseException ignore)
{
// Do nothing
}
}
return false;
}
/**
* Return true if the request URI is secure according to isUriSecure().
*
* @return True if the request URI is secure according to
* isUriSecure(), otherwise false.
*/
private boolean isRequestUriSecure()
{
return isUriSecure(getRequestURI());
}
/**
* Return true if the request URI is secure according to isUriUsingSips().
*
* @return True if the request URI is secure according to
* isUriUsingSips(), otherwise false.
*/
private boolean isRequestUriUsingSips()
{
return isUriUsingSips(getRequestURI());
}
/**
* Returns true if URI is a SipURI and either has the secure flag set
* or has the transport parameter set to TLS.
*
* @param uri The URI to check.
* @return True if URI is a SipURI and either has the secure flag set
* or has the transport parameter set to TLS, otherwise false.
*/
private boolean isUriSecure(URI uri)
{
if (uri.isSipURI())
{
SipURI sipUri = (SipURI) uri;
if (sipUri.isSecure() || (sipUri.getTransportParam() != null &&
sipUri.getTransportParam().equalsIgnoreCase("tls")))
{
return true;
}
}
return false;
}
/**
* Returns true if URI is a SipURI and has the secure flag set.
*
* @param uri The URI to check.
* @return True if URI is a SipURI and either has the secure flag set,
* otherwise false.
*/
private boolean isUriUsingSips(URI uri)
{
if (uri.isSipURI())
{
SipURI sipUri = (SipURI) uri;
return sipUri.isSecure();
}
return false;
}
private boolean isPushRouteAllowed() {
return isInitial() || getDialog().size() == 1;
}
public void restoreRetransmissionApplicationStack(Layer currentLayer) {
clearApplicationDispatchers();
Iterator<Layer> iter =
LayerHandler.getInstance().getLayers().iterator();
Layer l = null;
// lets iterate until and including ResolverManager...
while (iter.hasNext()) {
l = iter.next();
if("CANCEL".equals(getMethod()) &&
(l instanceof TransactionManager)) {
if (_logger.isLoggable(Level.FINE)) {
_logger.log(Level.FINE,
"TransactionManager not added for CANCEL " );
}
continue;
}
if (l.equals(currentLayer)) {
break;
}
pushApplicationDispatcher(l);
}
}
public void popTopVia() {
//Remove via
Header reqvia = getRawHeader(Header.VIA);
reqvia.setReadOnly(false);
ListIterator<String> via_li = reqvia.getValues();
String reqtopVia = via_li.next();
// TODO could match to see that it's the right host'n port
via_li.remove();
}
public List<TargetTuple> getFailedTargets() {
return _failedTargets;
}
public void addFailedTarget(TargetTuple failedTarget) {
_failedTargets.add(failedTarget);
}
}