Package com.ericsson.ssa.sip

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

/*
* 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 java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.security.AccessController;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.servlet.Servlet;
import javax.servlet.sip.Address;
import javax.servlet.sip.ServletParseException;
import javax.servlet.sip.SipApplicationSession;
import javax.servlet.sip.SipServletMessage;
import javax.servlet.sip.SipServletRequest;
import javax.servlet.sip.SipServletResponse;
import javax.servlet.sip.URI;

import org.apache.catalina.Globals;
import org.jvnet.glassfish.comms.util.LogUtil;


/**
* Responsible of the UAC and UAS behaviour.
*
* @author ehsroha
* @reviewed ejoelbi 2006-oct-19
*/
public class UA implements PathNode, Externalizable {
    private static final long serialVersionUID = -8507246342015896916L;
    private static final Logger m_Log = LogUtil.SIP_LOGGER.getLogger();
    private transient SipSessionManager m_sipSessionManager;
    private String m_sipApplicationSessionId;
    FSM m_InviteFsm = null;
    private final LinkedList<URI> m_RouteSet = new LinkedList<URI>();
    private Type m_Type = Type.Caller;
    private String m_sipSessionId;
    private int m_RemoteCSeq = -1;
    private Object _CSeqSynch = new Object();
    private int _inviteCSeq = -1;

    public UA(SipApplicationSessionImpl appSession, boolean isCaller) {
        this(appSession.getId(), isCaller, appSession.getSipSessionManager());
    }

    public UA(String appSessionId, boolean isCaller,
        SipSessionManager sipSessionManager) {
        m_sipApplicationSessionId = appSessionId;
        m_sipSessionManager = sipSessionManager;

        if (isCaller) {
            m_Type = Type.Caller;
        } else {
            m_Type = Type.Callee;
        }
    }

    // For serialization support
    public UA() {
    }

    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeObject(m_InviteFsm);
        out.writeInt(m_RouteSet.size());

        Iterator<URI> ui = m_RouteSet.iterator();

        while (ui.hasNext()) {
            out.writeObject(ui.next());
        }

        // TODO check if needed used for multidialogs e.g. within a subscribe
        // session
        // need to know how many concurrent sessions that are ongoing
        // private final Map<String, String> m_Sessions = new
        // ConcurrentHashMap<String, String>();
        if (m_Type == Type.Caller) {
            out.writeInt(1);
        } else if (m_Type == Type.Callee) {
            out.writeInt(2);
        } else {
            out.writeInt(3);
        }

        out.writeUTF(m_sipSessionManager.getApplicationId());
        out.writeUTF(m_sipSessionId);
        out.writeUTF(m_sipApplicationSessionId);
        out.writeInt(m_RemoteCSeq);

        // m_RemoteCSeqSynch = new Object();
    }

    public void readExternal(ObjectInput in)
        throws IOException, ClassNotFoundException {
        m_InviteFsm = (INVITESession) in.readObject();

        int i = in.readInt();

        for (int c = 0; c < i; c++) {
            m_RouteSet.add((URI) in.readObject());
        }

        switch (in.readInt()) {
        case 1:
            m_Type = Type.Caller;

            break;

        case 2:
            m_Type = Type.Callee;

            break;

        default:
            m_Type = Type.Undefined;
        }

        SipSessionManagerRegistry reg = null;

        if (Globals.IS_SECURITY_ENABLED) {
            reg = (SipSessionManagerRegistry) AccessController.doPrivileged(new PrivilegedGetSipSessionManagerRegistry());
        } else {
            reg = SipSessionManagerRegistry.getInstance();
        }

        if (reg != null) {
            m_sipSessionManager = reg.get(in.readUTF());
        }

        m_sipSessionId = in.readUTF();
        m_sipApplicationSessionId = in.readUTF();
        m_RemoteCSeq = in.readInt();
        _CSeqSynch = new Object();
    }

    private SipSessionBase findSipSession() {
        if (m_sipSessionId == null) {
            return null;
        }

        SipSessionBase result = null;

        try {
            result = m_sipSessionManager.findSipSession(m_sipSessionId);
        } catch (RemoteLockException e) {
            throw new RemoteLockRuntimeException(e);
        }

        return result;
    }

    private SipApplicationSessionImpl findSipApplicationSession() {
        if (m_sipApplicationSessionId == null) {
            return null;
        }

        SipApplicationSessionImpl result = null;

        try {
            result = m_sipSessionManager.findSipApplicationSession(m_sipApplicationSessionId);
        } catch (RemoteLockException e) {
            throw new RemoteLockRuntimeException(e);
        }

        return result;
    }

    public Type getType() {
        return m_Type;
    }

    private boolean isCaller() {
        return m_Type == Type.Caller;
    }

    /**
     * Returns whether all dialog creational sessions have been terminated or not
     *
     * @return whether all dialog creational sessions have been terminated or not
     */
    public boolean isEmptyDialogSession() {
        // Not implemented, optimization for application pgm
        // return m_Sessions.isEmpty();
        return true;
    }

    /**
     * If the touple method and id matches an existing session of this dialog
     * true is returned otherwise false.
     *
     * @param method
     *        is one of the touples of the key to find a session
     * @param id
     *        is one of the touples of the key to find a session. Some messages
     *        could create many sessions and to distinguish one session from
     *        another a unique id is used and together with the method a unique
     *        touple is formed.
     * @return whether the method and id touple will match an existing session
     */
    public boolean isDialogSession(String method, String id) {
        // Not implemented, optimization for application pgm
        // boolean isDialogSession = false;
        // if (method.equals("INVITE"))
        // {
        // isDialogSession = m_Sessions.contains(method);
        // }
        // else
        // {
        // isDialogSession = m_Sessions.contains(method + id);
        // }
        // return isDialogSession;
        return true;
    }

    /**
     * A message that is able to create a dialog (e.g. INVITE, SUBSCRIBE, REFER,
     * etc.) should be stored as a session and later removed when a terminating
     * message arrives. All methods that create dialog (INVITE, SUBSCRIBE, REFER,
     * etc) must use this function to inform that a session has been established.
     * When terminating a session the removeDialogSession MUST be used. A
     * SUBSCRIBE should also indicate which session id that has been used, which
     * is not necessary for an INVITE. NOTE: The re-INVITE and a SUBSCRIBE
     * updating the expire timer MAY not use this function.
     *
     * @param method
     *        is one of the touples of the key to store a session
     * @param id
     *        is one of the touples of the key to store a session. Some messages
     *        could create many sessions and to distinguish one session from
     *        another a unique id is used and together with the method a unique
     *        touple is formed.
     * @return the prevoius method that match if any, otherwise null
     */
    public boolean addDialogSession(String method, String id) {
        // Not implemented, optimization for application pgm
        // boolean value = false;
        // if (method.equals("INVITE"))
        // {
        // value = m_Sessions.add(method);
        // }
        // else
        // {
        // value = m_Sessions.add(method + id);
        // }
        // return value;
        return true;
    }

    /**
     * Removes the session.
     *
     * @param method
     *        is one of the touples of the key to remove a session
     * @param id
     *        is one of the touples of the key to remove a session. Some messages
     *        could create many sessions and to distinguish one session from
     *        another a unique id is used and together with the method a unique
     *        touple is formed.
     * @return the session that have been removed or if no match null is
     *         returned.
     */
    public boolean removeDialogSession(String method, String id) {
        // Not implemented, optimization for application pgm
        // boolean value = false;
        // if (method.equals("INVITE"))
        // {
        // value = m_Sessions.remove(method);
        // }
        // else
        // {
        // value = m_Sessions.remove(method + id);
        // }
        // return value;
        return true;
    }

    /**
     * Will shallow copy most of the member variables and returns a cloned
     * ua. If ua is invalid null is returned.
     *
     * @return a cloned ua. If ua is invalid null is returned.
     */
    public Object clone() {
        UA clone = new UA(m_sipApplicationSessionId, isCaller(),
                m_sipSessionManager);
        clone.m_InviteFsm = (m_InviteFsm != null) ? (FSM) m_InviteFsm.clone()
                                                  : null;
        clone.m_sipSessionId = m_sipSessionId;

        return clone;
    }
    /**
     * Returns the InviteFSM. Implemented for B2buaHelper.createCancel handling.
     */
    public INVITESession getInviteFSM() {
        if (this.m_InviteFsm != null) {
            return INVITESession.class.cast(this.m_InviteFsm);
        } else {
            return null;
        }
    }


    /**
     * Returns a state machine that could handle this message or null otherwise
     *
     * @param m
     *        the message indicating which state machine to use
     * @return a valid state machine that could handle this message or null
     *         otherwise
     */
    private FSM getFSM(SipServletMessage m) {
        FSM fsm = SUBSCRIBE_REFERSession.createFSM(m);

        if (fsm != null) {
            return fsm;
        }

        fsm = GeneralSession.createFSM(m);

        if (fsm != null) {
            return fsm;
        }

        if (m_InviteFsm == null) {
            synchronized (this) {
                if (m_InviteFsm == null) {
                    m_InviteFsm = INVITESession.createFSM(m);
                }
            }
        }

        return m_InviteFsm;
    }

    private void saveRemoteTarget(SipServletMessageImpl m,
        boolean contactIsMandatory) throws ServletParseException {
        Address contact = m.getAddressHeaderImpl(Header.CONTACT);

        if (contact != null) {
            findSipSession()
                .setRemoteTarget(m.getAddressHeaderImpl(Header.CONTACT).getURI());
        } else {
            if (contactIsMandatory) {
                if (m_Log.isLoggable(Level.FINE)) {
                    m_Log.log(Level.FINE,
                        "No Contact Header found, unable to continue this session, invalidating session: ");
                }

                findSipSession().invalidate();
                throw new IllegalStateException("Missing Contact header field");
            }
        }
    }

    /**
     * adds the route set to the message
     *
     * @param m
     */
    private void addRouteSet(SipServletMessageImpl m) {
        Iterator<URI> iter = m_RouteSet.iterator();

        while (iter.hasNext()) {
            Header routeHeader = new MultiLineHeader(Header.ROUTE, true);
            URI u = iter.next();
            routeHeader.setValue("<" + u.toString() + ">", false);
            m.addHeader(routeHeader);
        }
    }

    /**
     * Saves the route set in order from Record-Route
     */
    private void saveRouteSet(SipServletRequest req)
        throws ServletParseException {
        String dummy = req.getHeader(Header.RECORD_ROUTE);

        if (dummy == null) {
            return;
        }

        //Remove after fixing issue 85
        ListIterator<Address> iter = req.getAddressHeaders(Header.RECORD_ROUTE);
        Address addr = null;
        // RFC 12.1.1
        // If no Record-Route header field is present in the
        // request, the route set MUST be set to the empty set.
        // This route set, even if empty, overrides any pre-existing route set for
        // future requests in this dialog.
        m_RouteSet.clear();

        while (iter.hasNext()) {
            addr = (Address) iter.next();
            m_RouteSet.add(addr.getURI());
        }
    }

    /**
     * Saves the route set in reverse order from Record-Route
     */
    private void saveRouteSet(SipServletResponse resp)
        throws ServletParseException {
        ListIterator<Address> iter = resp.getAddressHeaders("Record-Route");
        Address addr = null;
        // RFC 12.1.2
        // If no Record-Route header field is present in the
        // request, the route set MUST be set to the empty set.
        // This route set, even if empty, overrides any pre-existing route set for
        // future requests in this dialog.
        m_RouteSet.clear();

        while (iter.hasNext()) {
            addr = (Address) iter.next();
            m_RouteSet.addFirst(addr.getURI());
        }
    }

    private boolean isLooseRoute() {
        boolean toReturn = false;

        if ((m_RouteSet != null) && !m_RouteSet.isEmpty()) {
            URI uri = m_RouteSet.getFirst();
            URIImpl uriImpl = (URIImpl) uri;
            toReturn = uriImpl.getLrParam();
        }

        return toReturn;
    }

    /**
     * Always used by the servlet entity acting as a UAC for the particular
     * request.
     *
     * @param req
     * @throws java.io.IOException
     * @throws java.lang.IllegalStateException
     */
    public void send(SipServletRequestImpl req)
        throws java.io.IOException, java.lang.IllegalStateException {
        OutboundInterface.resolve(req);
        FSM fsm = getFSM(req);

        if (fsm != null) {
            if (req.isInitial()) {
                m_sipSessionId = req.getSessionImpl().getId();
            } else {
                // RFC 3261, 12.2.1.1
                if (!req.getMethod().equals("CANCEL")) {
                    if (m_RouteSet.isEmpty()) {
                        req.setRequestURI(getRemoteTarget());
                    } else if (isLooseRoute()) {
                        req.setRequestURI(getRemoteTarget());
                        addRouteSet(req);
                    } else {
                        if (m_Log.isLoggable(Level.FINE)) {
                            m_Log.log(Level.FINE,
                                "NOT IMPLEMENTED: strict routing; cannot send request: " +
                                req);
                        }

                        throw new IllegalStateException(
                            "Strict routing not implemented");
                    }
                }
            }

            // invoke fsm
            fsm.send(req, this);
        } else {
            if (m_Log.isLoggable(Level.FINE)) {
                m_Log.log(Level.FINE,
                    "No state machine for request could be found: " +
                    req.toDebugString());
            }
        }
    }

    public void saveContactRouteSetRemoteTarget(SipServletRequestImpl req)
        throws ServletParseException {
        if (getRemoteTarget() == null) {
            synchronized (this) {
                // double-checked locking pattern
                if (getRemoteTarget() == null) {
                    // save route set and remote target
                    // RFC 3261, 12.1.1
                    saveRouteSet(req);
                    saveRemoteTarget(req, true);
                }
            }
        }
    }


         
    public synchronized void saveContactRemoteTarget(SipServletResponseImpl resp) throws ServletParseException
    {
       HeaderRequirement contactRequirement = SipFactoryImpl.getContactRequirement(resp);

       if (contactRequirement != HeaderRequirement.NOT_APPLICAPLE) {
           saveRemoteTarget(resp.getRequestImpl(),
               contactRequirement == HeaderRequirement.MANDATORY);
       }
    }
   
    public void saveContactRouteSetRemoteTarget(SipServletResponseImpl resp)
        throws ServletParseException {
        if (getRemoteTarget() == null) {
            synchronized (this) {
                // double-checked locking pattern
                if (getRemoteTarget() == null) {
                    SipServletRequest req = resp.getRequest();
                    // save route set and remote target
                    // RFC 3261, 12.1.1
                    saveRouteSet(req);

                    saveContactRemoteTarget(resp);
                }
            }
        }
    }

    /**
     * Always used by the servlet entity acting as a UAS for the particular
     * response.
     *
     * @param resp
     * @throws java.io.IOException
     * @throws java.lang.IllegalStateException
     */
    public void send(SipServletResponseImpl resp)
        throws java.io.IOException, java.lang.IllegalStateException {
        OutboundInterface.resolve(resp);
        FSM fsm = getFSM(resp);

        if (fsm != null) {
            if (resp.getRequest().isInitial() && (m_RemoteCSeq == -1)) {
                setInviteCSeq(resp.getRequestImpl());
                setRemoteCSeq(resp.getRequestImpl());
            }

            // invoke fsm
            fsm.send(resp, this);
        } else {
            if (m_Log.isLoggable(Level.FINE)) {
                m_Log.log(Level.FINE,
                    "No state machine for response could be found: " +
                    resp.toDebugString());
            }
        }
    }

    /**
     * Always used by the Dispatcher to access the UAS
     */
    public void dispatch(SipServletRequestImpl req) {
      if(!validateSessionState()){
        m_Log.log(Level.FINE,"UA is not handling request as SipSession or SipApplicationSession are missing or invalid");
        return;
      }      
      FSM fsm = getFSM(req);

        if (fsm != null) {
            if (m_RemoteCSeq == -1) {
                // Since remote CSeq is not saved lets do it...
                boolean success = setRemoteCSeq(req);

                if (!success) {
                    // raise condition occured, lets verify..
                    success = verifyAndUpdateCSeq(req);

                    if (!success) {
                        // CSeq is lower than allowed, send error response...
                        // TR HH52078
                        SipServletResponseImpl resp = req.createTerminatingResponse(500);

                        if (resp == null) {
                            return;
                        }

                        resp.popDispatcher().dispatch(resp);

                        return;
                    }
                }
            } else {
                // lets verify...
                if (!req.getMethod().equals("ACK")) // FIXME, if PRACK is used CSeq
                                                    // is increased
                 {
                    boolean success = verifyAndUpdateCSeq(req);

                    if (!success) {
                        // CSeq is lower than allowed, send error response...
                        SipServletResponseImpl resp = req.createTerminatingResponse(500);
                        resp.popDispatcher().dispatch(resp);

                        return;
                    }
                }
            }

           
            SecurityInterceptor si = SecurityInterceptor.getInstance();
            AuthModule module = this.getApplicationSession().getServletDispatcher().getAuthModule();
            String servletToInvoke = this.getSipSession().getHandler();
            try {
                if (!si.verifyRequest(req, module, servletToInvoke)) {
                    return;
                }
            } catch (IOException ex) {
                m_Log.log(Level.SEVERE, null, ex);
                return ;
            }
            try {
                fsm.dispatch(req, this);
            } catch (RemoteLockRuntimeException e) {
                SipServletResponseImpl resp = req.createTerminatingResponse(500);
                resp.setHeader(Header.RETRY_AFTER, "5");
                resp.popDispatcher().dispatch(resp);

                return;
            }
        } else {
            if (m_Log.isLoggable(Level.FINE)) {
                m_Log.log(Level.FINE,
                    "No state machine for request could be found: " +
                    req.toDebugString());
            }
        }
    }

    public void saveTargetRefreshContact(SipServletResponseImpl resp)
        throws ServletParseException {
        synchronized (this) {
            HeaderRequirement contactRequirement = SipFactoryImpl.getContactRequirement(resp);
            if (contactRequirement != HeaderRequirement.NOT_APPLICAPLE) {
                saveRemoteTarget(resp,
                    contactRequirement == HeaderRequirement.MANDATORY);
             }
         }
    }


    public void saveRouteSetRemoteTarget(SipServletResponseImpl resp)
        throws ServletParseException {
        if (getRemoteTarget() == null) {
            synchronized (this) {
                if (getRemoteTarget() == null) // double-checked locking pattern
                 {
                    // add route set and remote target
                    // RFC 3261, 12.1.2
                    saveRouteSet(resp);

                    HeaderRequirement contactRequirement = SipFactoryImpl.getContactRequirement(resp);

                    if (contactRequirement != HeaderRequirement.NOT_APPLICAPLE) {
                        saveRemoteTarget(resp,
                            contactRequirement == HeaderRequirement.MANDATORY);
                    }
                }
            }
        }
    }

    /**
     * Always used by the Dispatcher to access the UAC
     */
    public void dispatch(SipServletResponseImpl resp) {
      if(!validateSessionState()){
        m_Log.log(Level.FINE,"UA is not handling response as SipSession or SipApplicationSession are missing or invalid");
        return;
      }

        FSM fsm = getFSM(resp);

        if (fsm != null) {
            try {
                fsm.dispatch(resp, this);
            } catch (RemoteLockRuntimeException e) {
                if (m_Log.isLoggable(Level.FINE)) {
                    m_Log.log(Level.FINE,
                        "Could not dispatch response since the dialog was remotely locked: " +
                        resp.toDebugString());
                }

                return;
            }
        } else {
            if (m_Log.isLoggable(Level.FINE)) {
                m_Log.log(Level.FINE,
                    "No state machine for response could be found: " +
                    resp.toDebugString());
            }
        }
    }

    /**
     * Checks that sessions (SipApplicationSession and SipSession) for this UA are still valid
     *
     * @return Whether sessions are valid or not. If false is returned, a good thing would be not to proceed.
     */
    private boolean validateSessionState() {
      SipSessionBase sipSession =  getSipSession();
      if(sipSession==null){
        return false;
      }
      if(!sipSession.isValid()){
        return false;
      }
      SipApplicationSession sipApplicationSession = getApplicationSession();
      if(sipApplicationSession==null){
        return false;
      }
      return sipApplicationSession.isValid();
  }

  public SipSessionBase getSipSession() {
        return findSipSession();
    }

    public String getSipSessionId() {
        return m_sipSessionId;
    }

    public SipSessionManager getSipSessionManager() {
        return m_sipSessionManager;
    }

    public void setSipSession(SipSessionBase s) {
        s.setType(getType());
        m_sipSessionId = s.getId();
    }

    public SipApplicationSessionImpl getApplicationSession() {
        return findSipApplicationSession();
    }

    public Servlet getServlet(String handler) {
        return SipFactoryImpl.getInstance().getServiceHandler()
                             .getHandler(getApplicationSession().getName(),
            handler);
    }

    /**
     * Sets the INVITE CSeq value received from remote
     * to later verify CANCEL or ACK.
     *
     * @param req
     *        request holding the INVITE CSeq value
     * @return false if starting point was already set
     * @throws NumberFormatException
     */
    private void setInviteCSeq(SipServletRequestImpl req)
        throws NumberFormatException {
        if (req.getMethod().equals("INVITE")) {
            synchronized (_CSeqSynch) {
                _inviteCSeq = req.getCSeqNumber();
            }
        }
    }

    /**
     * Sets the starting CSeq value received from remote
     *
     * @param req
     *        request holding the starting CSeq value
     * @return false if starting point was already set
     * @throws NumberFormatException
     */
    private boolean setRemoteCSeq(SipServletRequestImpl req)
        throws NumberFormatException {
        boolean success = false;

        synchronized (_CSeqSynch) {
            if (m_RemoteCSeq == -1) {
                m_RemoteCSeq = req.getCSeqNumber();
                success = true;
            }
        }

        return success;
    }

    /**
     * Verifies that the CSeq value generated by the remote side is strictly
     * monotonically increasing and contiguous. NOTE: ACK and CANCEL should have
     * same value as INVITE.
     *
     * @param m
     * @return false if CSeq is lower than accepted otherwise true
     * @throws NumberFormatException
     */
    private boolean verifyAndUpdateCSeq(SipServletRequestImpl req)
        throws NumberFormatException {
        boolean success = false;
        int messageCSeq = req.getCSeqNumber();
        int CSeq = -1;

        if (req.getMethod().equals("ACK") || req.getMethod().equals("CANCEL")) {
            // ACK and CANCEL should have same CSeq as INVITE
            synchronized (_CSeqSynch) {
                CSeq = _inviteCSeq;
                success = (messageCSeq == CSeq);
            }
        } else if (req.getMethod().equals("INVITE")) {
            if (messageCSeq > _inviteCSeq) {
                synchronized (_CSeqSynch) {
                    _inviteCSeq = messageCSeq;
                    success = true;
                }
            }
        } else {
            // RFC3261, 12.2.2. If the remote sequence number was not
            // empty, but the sequence number of the request is lower
            // than the remote sequence number, the request is out of
            // order. If the remote sequence number was not empty, and
            // the sequence number of the request is greater than the
            // remote sequence number, the request is in order. The UAS
            // MUST then set the remote sequence number to the value of
            // the sequence number in the CSeq header field value in the
            // request.
            synchronized (_CSeqSynch) {
                CSeq = m_RemoteCSeq;

                if (messageCSeq > CSeq) {
                    m_RemoteCSeq = messageCSeq;
                    success = true;
                }
            }
        }

        return success;
    }

    public URI getRemoteTarget() {
        SipSessionBase session = findSipSession();

        return (session != null) ? session.getRemoteTarget() : null;
    }

    /**
     * Returns true if this PathNode is replicable, false otherwise.
     *
     * @return true if this PathNode is replicable, false otherwise
     */
    public boolean isReplicable() {
        return findSipApplicationSession().isReplicable();
    }

    /**
     * Sets the remote CSEQ. Note, this method is only to be used at restore of DialogFragment.
     * @param cseq
     */
    void setRemoteCSeq(int cseq) {
        m_RemoteCSeq = cseq;
    }

    /**
     * Gets the remote CSEQ. Note, this method is only to be used at restore of DialogFragment.
     * @return The remote CSEQ
     */
    int getRemoteCSeq() {
        return m_RemoteCSeq;
    }
}
TOP

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

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.