Package com.ericsson.ssa.sip

Source Code of com.ericsson.ssa.sip.SipFactoryImpl

/*
* 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.container.SipBindingResolver;
import org.jvnet.glassfish.comms.deployment.backend.SessionCase;

import org.jvnet.glassfish.comms.security.auth.impl.AuthInfoImpl;

import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Level;

// inserted by hockey (automatic)
import org.jvnet.glassfish.comms.util.LogUtil;
import java.util.logging.Logger;

import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.sip.Address;
import javax.servlet.sip.AuthInfo;
import javax.servlet.sip.Parameterable;
import javax.servlet.sip.ServletParseException;
import javax.servlet.sip.ar.SipApplicationRoutingDirective;
import javax.servlet.sip.SipApplicationSession;
import javax.servlet.sip.SipFactory;
import javax.servlet.sip.SipServletRequest;
import javax.servlet.sip.SipServletResponse;
import javax.servlet.sip.SipURI;
import javax.servlet.sip.URI;


/**
* @author ekrigro
* @reviewed ejoelbi 2006-oct-19
*/
public class SipFactoryImpl implements SipFactory {
    public static final String SIP_CHARSET = "UTF-8";
    public static final String PROTOCOL_LINE = "SIP/2.0";
    public static final String NEW_LINE = "\r\n";
    public static final String SIP_URI_PROTOCOL = "sip";
    public static final String HTTP_URI_PROTOCOL = "http";
    public static final String MAILTO_URI_PROTOCOL = "mailto";
    public static final String SIPS_URI_PROTOCOL = "sips";
    public static final String TEL_URI_PROTOCOL = "tel";
    public static final String SUPPORTED_100REL = "100rel";
    public static final String REMOTE_TARGET = "com.ericsson.ssa.RemoteTarget";
    public static final int START_CSEQ = 1;
    private static AtomicInteger m_GlobalCallID = new AtomicInteger(1);
    private static AtomicLong m_GlobalTag = new AtomicLong(1);
    private static ServiceHandler m_ServiceHandler = null;
    private static final SipFactoryImpl _instance = new SipFactoryImpl();
    private static final Logger _log = LogUtil.SIP_LOGGER.getLogger();
    public static final int SIP_RFC_PORT = 5060;
    public static final int SIPS_RFC_PORT = 5061;
    private static Pattern p =Pattern.compile("^([a-zA-Z])+([\\w+-.])*$");

    private static boolean ocsInterop =
    Boolean.getBoolean("org.glassfish.sip.ocsInteroperable");

    // initial
    // value
    // needed
    // by
    // JUnit
    // tests
    public static SipFactoryImpl getInstance() {
        return _instance;
    }

    public URI createURI(String uri) throws ServletParseException {
        try {
            // search for the protocol
            String protocol = null;

            int position = 0;
            int cnt = 0;
            int length = uri.length();
            while ((cnt < length) && (uri.charAt(cnt) != ':')) {
                cnt++;
            }
            protocol = uri.substring(position, cnt);

            Matcher m = p.matcher(protocol);

            if (!m.find()) {
                throw new ServletParseException("URI does not conform to BNF :" + protocol);
            }

            if (protocol.equals(SIP_URI_PROTOCOL)) {
                return new SipURIImpl(SIP_URI_PROTOCOL, uri, cnt + 1);
            }

            if (protocol.equals(TEL_URI_PROTOCOL)) {
                return new TelURLImpl(uri, cnt + 1);
            }

            if (protocol.equals(SIPS_URI_PROTOCOL)) {
                return new SipURIImpl(SIPS_URI_PROTOCOL, uri, cnt + 1);
            }

            //JSR 289 SipFactory.createURI says, implementation should be able
            //to handle any scheme. So, create a GeneralURIImpl.
            return new GeneralURIImpl(protocol, uri, cnt + 1);
        } catch (Throwable t) {
            throw new ServletParseException(t);
        }
    }

    public SipURI createSipURI(String user, String host) {
        SipURI uri = new SipURIImpl();
        uri.setHost(host);
        uri.setUser(user);

        return uri;
    }

    public Address createAddress(String sipAddress)
        throws ServletParseException {
        return new AddressImpl(sipAddress);
    }

    public Address createAddress(URI uri) {
        return new AddressImpl(uri);
    }

    public Address createAddress(URI uri, String displayName) {
        Address result = new AddressImpl(uri);
        result.setDisplayName(displayName);

        return result;
    }

    public SipServletRequestImpl createRequest(
        SipApplicationSession appSession, String method, Address from,
        Address to) {
        return createRequestImpl((SipApplicationSessionImpl) appSession,
                method, from, to, false, null);
    }

    private void createSession(SipServletRequestImpl req,
        SipApplicationSessionImpl appSess, String handlerName)  {
        // creates a new sip session and dialog structure
        DialogSet ds = new DialogSet(req.getMethod(), req.getCallId(), req.getFromImpl(),
                req.getBeKey(), SipFactoryImpl.isDialogCreational(req.getMethod()));       
        req.setDialog(ds.getInitialDialogFragment());

        DialogFragment d = req.getDialog();
        SipSessionBase s = appSess.getSipSessionManager()
                                  .createSipSession(d.getDialogSet(),
                req.getToImpl(), appSess, handlerName);
        req.setSession(s);
        d.getDialogLifeCycle().initUnitOfWork();
    }

    private URI cleanupFromOrToURI(URI fromOrTo) {
        // port, method, maddr, ttl,transport,lr parameters and headers
        // need to be removed from the URIs

        fromOrTo.removeParameter("port");
        fromOrTo.removeParameter("method");
        fromOrTo.removeParameter("maddr");
        fromOrTo.removeParameter("ttl");
        fromOrTo.removeParameter("transport");
        fromOrTo.removeParameter("lr");

        if (fromOrTo.isSipURI()) {
            SipURI sURI = (SipURI)fromOrTo;
            Iterator<String> headerNames = sURI.getHeaderNames();
            while (headerNames.hasNext()) {
                sURI.removeHeader(headerNames.next());
            }
        }
        return fromOrTo;
    }

    public SipServletRequestImpl createRequestImpl(
        SipApplicationSessionImpl appSession, String method, Address from,
        Address to, boolean sameCallID, SipServletRequestImpl origRequest) {
        if (!method.equals("ACK") && !method.equals("CANCEL")) {
            Address fromCopy = (Address) from.clone();
            Address toCopy = (Address) to.clone();

            // Remove protection, lock up
            ((AddressImpl) fromCopy).setReadOnly(false);
            ((AddressImpl) toCopy).setReadOnly(false);
            fromCopy.setParameter(AddressImpl.TAG_PARAM, createTag());
            toCopy.removeParameter(AddressImpl.TAG_PARAM);


            SipServletRequestImpl req = null;
            String defaultHandler = null;

            if (origRequest == null) {
                URI requestURI = (URI) toCopy.getURI().clone();
                if ("REGISTER".equals(method) && requestURI.isSipURI()) {
                    ((SipURI)requestURI).setUser(null);
                }
                req = new SipServletRequestImpl(method, requestURI,
                        SipFactoryImpl.PROTOCOL_LINE);
               req.setInternalRoutingDirective(
                        SipApplicationRoutingDirective.NEW, null);
               req.setBeKey(appSession.getBeKey());
            } else {
                req = (SipServletRequestImpl) origRequest.clone();
                req.setInternalRoutingDirective(
                        SipApplicationRoutingDirective.CONTINUE, origRequest);
                // copy region in case of CONTINUE as well
                req.setRegion(origRequest.getRegion());
                req.clearApplicationDispatchers();
                // The clone will copy the session-case. For the new request
                // the session-case should be internal.
                req.setSessionCase(SessionCase.INTERNAL);
                req.removeSystemHeaders();
                req.removeRemoteSettings();
                defaultHandler = origRequest.getSessionImpl().getHandler();
            }

            // set CallID
            Header callIDHeader = new SingleLineHeader(Header.CALL_ID, true);

            if ((origRequest == null) || !sameCallID) {
                callIDHeader.setValue(createCallID(), false);
            } else {
                callIDHeader.setValue(origRequest.getCallId(), false);
            }

            req.setHeader(callIDHeader);

            URI fromURI = cleanupFromOrToURI(fromCopy.getURI().clone());
            fromCopy.setURI(fromURI);
            URI toURI = cleanupFromOrToURI(toCopy.getURI().clone());
            toCopy.setURI(toURI);

            // Put protection, lock again
            ((AddressImpl) fromCopy).setReadOnly(true);
            ((AddressImpl) toCopy).setReadOnly(true);
        

            Header toHeader = new SingleLineHeader(Header.TO, true);
            toHeader.setAddressValue(toCopy, false);
            req.setHeader(toHeader);

            Header fromHeader = new SingleLineHeader(Header.FROM, true);
            fromHeader.setAddressValue(fromCopy, false);
            req.setHeader(fromHeader);
            req.setMaxForwards(70);

            if (defaultHandler == null) {
                defaultHandler = appSession.getCurrentServlet();
            }

            createSession(req, appSession, defaultHandler);

            // MUST be placed after createSession is called
            // Add the contact header if the request method is one of
            // INVITE, REFER, SUBSCRIBE eller NOTIFY.
            if (isDialogCreational(req.getMethod())) {
                DialogManager.getInstance().addContact(req);
            }

            Header cSeqHeader = new SingleLineHeader(Header.CSEQ, true);
            cSeqHeader.setValue(Integer.toString(START_CSEQ) + " " +
                req.getMethod(), false);
            req.setHeader(cSeqHeader);
            req.setInitial(true);

            List<Layer> layers = LayerHandler.getInstance().getLayers();
            req._applicationStack.addAll(layers);
            return req;
        }

        throw new IllegalArgumentException(
            "ACK and CANCEL is not allowed to create here.");
    }

    public SipServletRequestImpl createRequest(
        SipApplicationSession appSession, String method, URI from, URI to) {
        return createRequest(appSession, method, createAddress(from),
            createAddress(to));
    }

    public SipServletRequestImpl createRequest(
        SipApplicationSession appSession, String method, String from, String to)
        throws ServletParseException {
        return createRequest(appSession, method, createAddress(from),
            createAddress(to));
    }


    @Deprecated
    public SipServletRequestImpl createRequest(SipServletRequest origRequest,
        boolean sameCallId) {
        SipServletRequestImpl origRequestImpl = (SipServletRequestImpl) origRequest;
        SipServletRequestImpl req;
        req = createRequestImpl((SipApplicationSessionImpl) origRequest.getApplicationSession(),
                origRequest.getMethod(), origRequestImpl.getFromImpl(),
                origRequestImpl.getToImpl(), sameCallId, origRequestImpl);

        // HG54598, copy the Route header
        Header route = origRequestImpl.getRawHeader(Header.ROUTE);

        if (route != null) {
            req.setHeader((Header) route.clone());
        }

        // HH20252, copy the Contact header
        Header contact = origRequestImpl.getRawHeader(Header.CONTACT);

        if ((contact != null) && req.getMethod().equals("REGISTER")) {
            req.setHeader((Header) contact.clone());
        }

        return req;
    }

    public SipApplicationSessionImpl createApplicationSession() {
        /*
         * This method should never be called and therefore always returns null.
         * We only call createApplicationSession() on the context specific
         * facade of this singleton, which delegates the creation of the
         * SipApplicationSession to the context's associated session manager
         */
        return null;
    }

    /**
     * Returns a unique to tag.
     */
    public String createTag() {
        StringBuilder sb = new StringBuilder(
                Long.toString(System.currentTimeMillis(),
                36)).append('-').append(Long.toString(
                m_GlobalTag.getAndIncrement(), 36));

        return sb.toString();
    }

    /**
     * Returns a unique Call-ID.
     */
    public String createCallID() {
        if (ocsInterop) {
            return createCallID32Max();
        }
        int id = m_GlobalCallID.getAndIncrement();
        long r = Math.abs(new Random().nextLong());
        StringBuilder sb = new StringBuilder();
        sb.append(SipBindingResolver.instance().getCurrentPublicHost());
        sb.append('_').append(id).append('_').append(r);

        return sb.toString();
    }

    /**
     * Returns a unique Call-ID. The maximum length of the call-id should
     * be 32 for OCS. This method returns the call-id with max length of 32.
     * RFC 3261 indicate that the hostname should be part of the callid. However
     * if we add hostname as is, most of 32 length will be taken away by
     * hostname (especially when ipv6 is used). The remaining parts of the callid
     * may not guarantee uniqueness, especially when multiple instances are in
     * the same box.
     * So the callid will be
     * (hashcode of host address)_(an incremented number)_(randon number)
     */
    public String createCallID32Max() {
        if (_log.isLoggable(Level.FINER)) {
            _log.log(Level.FINER, "Creating call id with max 32 length");
        }

        int h = Math.abs(SipBindingResolver.instance().getCurrentPublicHost().hashCode());
        int id = m_GlobalCallID.getAndIncrement();
        int r = Math.abs(new Random().nextInt());       

        StringBuilder sb = new StringBuilder();
        sb.append(h).append('_').append(id).append('_').append(r);
        return sb.toString();
    }

    public Parameterable createParameterable(String s)
        throws ServletParseException {
        return ParameterableImpl.parse(s);
    }

    public ServiceHandler getServiceHandler() {
        return m_ServiceHandler;
    }

    public void setServiceHandler(ServiceHandler s) {
        m_ServiceHandler = s;
    }
   
    // As per section 4.1.3 of JSR 289, determine if contact is allowed
    // to be added in the servlet.
    public static boolean contactAllowedFromServlet(SipServletResponse resp) {
        int status = resp.getStatus();
        String method = resp.getMethod();
        if (((status >= 300) && (status < 400)) || (status == 485)) {
            return true;
        }

        if ("REGISTER".equals(method)) {
            return true;
        }

        if ("OPTIONS".equals(method)) {
            return status == 200;
        }

        return false;
    }

    /**
     * Check if the Contact header can be added (mandatory or optional in RFC) to
     * the response, according to the followning RFC's
     * <ul>
     * <li>RFC 3311</li>
     * <li>RFC 3262</li>
     * <li>RFC 3428</li>
     * <li>RFC 3261</li>
     * <li>RFC 3265</li>
     * <li>RFC 3515 </li>
     * </ul>
     *
     * @param resp
     *           The status code and SIP method will be used when performing the
     *           check.
     * @return true if the Contact header can be added to the response.
     */
    public static HeaderRequirement getContactRequirement(
        SipServletResponse resp) {
        int status = resp.getStatus();
        String method = resp.getMethod();

        if ("BYE".equals(method)) // RFC 3261
         {
            if (((status >= 300) && (status < 400)) || (status == 485)) {
                return HeaderRequirement.OPTIONAL;
            }
        }

        if ("INVITE".equals(method)) // RFC 3261
         {
            if ((status > 100) && (status < 200)) {
                return HeaderRequirement.OPTIONAL;
            }

            if ((status >= 200) && (status < 300)) {
                return HeaderRequirement.MANDATORY;
            }

            if (((status >= 300) && (status < 400)) || (status == 485)) {
                return HeaderRequirement.OPTIONAL;
            }
        }

        if ("OPTION".equals(method) || "REGISTER".equals(method)) // RFC 3261
         {
            if (((status >= 200) && (status < 400)) || (status == 485)) {
                return HeaderRequirement.OPTIONAL;
            }
        }

        if ("SUBSCRIBE".equals(method)) // RFC-3265
         {
            if ((status >= 100) && (status < 200)) {
                return HeaderRequirement.OPTIONAL;
            }

            if ((status >= 200) && (status < 400)) {
                return HeaderRequirement.MANDATORY;
            }

            if (status == 485) {
                return HeaderRequirement.OPTIONAL;
            }
        }

        if ("NOTIFY".equals(method)) // RFC-3265
         {
            if ((status >= 100) && (status < 300)) {
                return HeaderRequirement.OPTIONAL;
            }

            if ((status >= 300) && (status < 400)) {
                return HeaderRequirement.MANDATORY;
            }

            if (status == 485) {
                return HeaderRequirement.OPTIONAL;
            }
        }

        if ("REFER".equals(method)) // RFC 3515
         {
            if ((status >= 200) && (status < 300)) {
                return HeaderRequirement.MANDATORY;
            }

            if ((status >= 300) && (status < 700)) {
                return HeaderRequirement.OPTIONAL;
            }
        }

        if ("UPDATE".equals(method)) // RFC 3311
         {
            if ((status >= 100) && (status < 200)) {
                return HeaderRequirement.OPTIONAL;
            }

            if ((status >= 200) && (status < 300)) {
                return HeaderRequirement.MANDATORY;
            }

            if (((status >= 300) && (status < 400)) || (status == 485)) {
                return HeaderRequirement.OPTIONAL;
            }
        }

        if ("MESSAGE".equals(method)) // RFC 3428
         {
            if (((status >= 300) && (status < 400)) || (status == 485)) {
                return HeaderRequirement.OPTIONAL;
            }
        }

        if ("PRACK".equals(method)) // RFC 3262
         {
            if (((status >= 300) && (status < 400)) || (status == 485)) {
                return HeaderRequirement.OPTIONAL;
            }
        }

        return HeaderRequirement.NOT_APPLICAPLE;
    }

    public static boolean isDialogCreational(String method) {
        return method.equals("SUBSCRIBE") || method.equals("INVITE") ||
        method.equals("REFER") || method.equals("NOTIFY");
    }

    public static boolean initialRequestPossible(String method) {
        return !(method.equals("PRACK") ||
        method.equals("BYE") || method.equals("UPDATE") ||
        method.equals("ACK") || method.equals("INFO"));
    }

    public static boolean isContactMandatory(SipServletRequest req) {
        return isDialogCreational(req.getMethod()) ||
        req.getMethod().equals("UPDATE");
    }

    public AuthInfo createAuthInfo() {
        return new AuthInfoImpl();
    }

    public SipApplicationSession createApplicationSessionByAppName(
            String sipAppName) {
        // This method is only implemented by the Facade
        return null;
    }

    public SipApplicationSession createApplicationSessionByKey(
            String sipApplicationKey) {
        // This method is only implemented by the Facade
        return null;
    }
}
TOP

Related Classes of com.ericsson.ssa.sip.SipFactoryImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.