Package org.jvnet.glassfish.comms.sipagent.model

Source Code of org.jvnet.glassfish.comms.sipagent.model.MySipParser

/*
* The contents of this file are subject to the terms
* of the Common Development and Distribution License
* (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/CDDLv1.0.html or
* glassfish/bootstrap/legal/CDDLv1.0.txt.
* See the License for the specific language governing
* permissions and limitations under the License.
*
* When distributing Covered Code, include this CDDL
* Header Notice in each file and include the License file
* at glassfish/bootstrap/legal/CDDLv1.0.txt. 
* If applicable, add the following below the CDDL Header,
* with the fields enclosed by brackets [] replaced by
* you own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* Copyright (c) Ericsson AB, 2004-2007. All rights reserved.
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
*/
package org.jvnet.glassfish.comms.sipagent.model;

import com.ericsson.ssa.sip.AddressHeaderValidator;
import com.ericsson.ssa.sip.CSeqHeaderValidator;
import com.ericsson.ssa.sip.CallIDValidator;
import com.ericsson.ssa.sip.MandatoryHeaderValidator;
import com.ericsson.ssa.sip.SipFactoryImpl;
import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.ListIterator;
import javax.servlet.sip.SipFactory;
import javax.servlet.sip.URI;

// inserted by hockey (automatic)
import java.util.logging.Logger;
import java.util.logging.Level;

import com.ericsson.ssa.container.SipParserErrorHandler;
import com.ericsson.ssa.sip.Header;
import com.ericsson.ssa.sip.MaxForwardsValidator;
import com.ericsson.ssa.sip.SipServletMessageImpl;
import com.ericsson.ssa.sip.SipServletRequestImpl;
import com.ericsson.ssa.sip.SipServletResponseImpl;
import com.ericsson.ssa.sip.ViaHeaderValidator;
import com.ericsson.ssa.sip.dns.SipTransports;
import com.ericsson.ssa.sip.dns.TargetTuple;
import javax.servlet.sip.ServletParseException;

/**
* This is a very nice class that no-one had javadoc'ed before.
*
* ehswolm 2006-12-01: I don't feel like formatting this code just right now...
*
* @author ???
* @reviewed eandbur 2006-dec-01
*/
public class MySipParser {

    private static Logger theirLog = (Logger) Logger.getLogger(
            "org.jvnet.glassfish.comms.sipagent.model.MySipParser");
    private static SipFactory sf = SipFactoryImpl.getInstance();
    private static MySipParser _instance = null;
    private ArrayList<MandatoryHeaderValidator> mandatoryHeaderValidators;

    // Prevent instance creation of this singleton.
    private MySipParser() {
        // Initialization of validators
        mandatoryHeaderValidators = new ArrayList<MandatoryHeaderValidator>();
        //mandatoryHeaderValidators.add(new CallIDValidator());
        //mandatoryHeaderValidators.add(new AddressHeaderValidator(Header.FROM));
        //mandatoryHeaderValidators.add(new AddressHeaderValidator(Header.TO));
        //mandatoryHeaderValidators.add(new CSeqHeaderValidator());
        //mandatoryHeaderValidators.add(new ViaHeaderValidator());
        //mandatoryHeaderValidators.add(new MaxForwardsValidator());
    }

    public synchronized static MySipParser getInstance() {
        if (_instance != null) {
            return _instance;
        }
        return _instance = new MySipParser();
    }

    public SipMessage parseMessage(
            SipServletMessageImpl message,
            ByteBuffer bb,
            InetSocketAddress local,
            TargetTuple remote,
            SipParserErrorHandler errorHandler)
            throws ParserException {
        int limit = bb.limit();
        long startTime = 0;
        long endTime;
        if (theirLog.isLoggable(Level.FINE)) {
            theirLog.log(Level.FINE, "Data is ready for process : " + limit);
        }
        if (theirLog.isLoggable(Level.FINE)) {
            startTime = System.nanoTime();
        }
        bb.rewind();
        byte[] bs = bb.array();
        // Process the first line
        int cnt = bb.position();
        boolean isRequest = false;
        boolean isResponse = false;
        while (message == null && cnt < limit) {
            try {
                int position = bb.position();
                int foundSipVersion = -1;
                isRequest = false;
                isResponse = false;
                while (cnt + 1 < limit && (bs[cnt] != '\r' || bs[cnt + 1] != '\n')) {
                    // there is room for the version string
                    if (!isRequest && !isResponse && cnt + 6 < limit && (bs[cnt] == 's' || bs[cnt] == 'S')) { // Check
                        // for
                        // ip/2.0
                        if ((bs[cnt + 1] == 'i' || bs[cnt + 1] == 'I') && (bs[cnt + 2] == 'p' || bs[cnt + 2] == 'P') && bs[cnt + 3] == '/' && bs[cnt + 4] == '2' && bs[cnt + 5] == '.' && bs[cnt + 6] == '0') {
                            foundSipVersion = cnt; // Marks begining of SIP/2.0
                            if (theirLog.isLoggable(Level.FINE)) {
                                theirLog.log(Level.FINE, "Found SIP/2.0 version at index = " + foundSipVersion);
                            }
                            // Check if it is at the end, then it is a request
                            if (cnt + 8 < limit && bs[cnt + 7] == '\r' && bs[cnt + 8] == '\n') {
                                isRequest = true;
                                cnt += 6;
                                if (theirLog.isLoggable(Level.FINE)) {
                                    theirLog.log(Level.FINE, "The message is a SIP request");
                                }
                            } else if (cnt + 7 < limit && bs[cnt + 7] == ' ') {
                                isResponse = true;
                                cnt += 7;
                                if (theirLog.isLoggable(Level.FINE)) {
                                    theirLog.log(Level.FINE, "The message is a SIP response");
                                }
                            } else // Not a valid SIP/2.0 string
                            {
                                cnt += 6;
                                if (theirLog.isLoggable(Level.FINE)) {
                                    theirLog.log(Level.FINE, "Not a valid SIP/2.0 string");
                                }
                                foundSipVersion = -1;
                            }
                        }
                    }
                    cnt++;
                }
                if (cnt + 2 < limit) {
                    bb.position(cnt + 2);
                } else {
                    theirLog.log(Level.WARNING, "returning null!");
                    return null;
                }
                if (theirLog.isLoggable(Level.FINE)) {
                    theirLog.log(Level.FINE, "The first line is : " + new String(bs, position, (cnt - position), SipFactoryImpl.SIP_CHARSET));
                }
                if (isRequest) {
                    int x = foundSipVersion - 2;
                    while (x > 0 && bs[x] != ' ') {
                        x--;
                    }
                    String reqUri = new String(bs, x + 1, (foundSipVersion - x - 2), SipFactoryImpl.SIP_CHARSET);
                    if (theirLog.isLoggable(Level.FINE)) {
                        theirLog.log(Level.FINE, "ReqUri = " + reqUri + " x = " + x + " len = " + (foundSipVersion - x - 2));
                    }
                    if (x == 0) {
                        // TODO point after CRLF
                        // bb.position()
                        if (theirLog.isLoggable(Level.FINE)) {
                            theirLog.log(Level.FINE, "Error in parser the first line is corrupt!");
                        }
                        return null;
                    }
                    // The rest is method
                    // TODO check for capital case e.g. INVITE
                    int foundMethod = x--;
                    while (x > 0 && bs[x] > 0x40 && bs[x] < 0x5B) {
                        x--;
                    }
                    String method = new String(bs, 0, (foundMethod - 0), SipFactoryImpl.SIP_CHARSET);
                    String nice = new String(bs, x + 1, (foundMethod - x + 1), SipFactoryImpl.SIP_CHARSET);
                    if (theirLog.isLoggable(Level.FINE)) {
                        theirLog.log(Level.FINE, "method = " + method + " nice = " + nice);
                    }
                    URI uri = sf.createURI(reqUri);
                    if (uri == null) {
                        if (theirLog.isLoggable(Level.FINE)) {
                            theirLog.log(Level.FINE, "Error could not create Request Uri.");
                        }
                        return null;
                    }
                    message = new SipServletRequestImpl(method, uri, SipFactoryImpl.PROTOCOL_LINE);
                    message.setLocal(local);
                    message.setRemote(remote);
                } else if (isResponse) { // Start after the SIP/2.0 token
                    int x = foundSipVersion + 8; // SIP/2.0 len +1
                    int start = foundSipVersion + 8;
                    while (x < cnt && bs[x] != ' ') {
                        x++;
                    }
                    String codeStr = new String(bs, start, (x - start), SipFactoryImpl.SIP_CHARSET);
                    String phrase = new String(bs, (x + 1), (cnt - x - 1), SipFactoryImpl.SIP_CHARSET);
                    if (theirLog.isLoggable(Level.FINE)) {
                        theirLog.log(Level.FINE, "codeStr = " + codeStr + " phrase = " + phrase);
                    }
                    int code = Integer.parseInt(codeStr);
                    if (699 < code || code < 100) {
                        if (theirLog.isLoggable(Level.FINE)) {
                            theirLog.log(Level.FINE, "Error code out of range in response : " + code);
                        }
                        return null;
                    }
                    message = new SipServletResponseImpl(null, SipFactoryImpl.PROTOCOL_LINE, code, phrase);
                    message.setLocal(local);
                    message.setRemote(remote);
                } else {
                    if (theirLog.isLoggable(Level.FINE)) {
                        theirLog.log(Level.FINE, "The URI is not a request nor a response!");
                    }
                    return null;
                }
            } catch (ServletParseException spe) {
                if (theirLog.isLoggable(Level.FINER)) {
                    theirLog.log(Level.FINER, "Error in parser", spe);
                }
                return null;
            } catch (UnsupportedEncodingException uee) {
                if (theirLog.isLoggable(Level.FINER)) {
                    theirLog.log(Level.FINER, "Error in parser", uee);
                }
                return null;
            } catch (RuntimeException re) {
                if (theirLog.isLoggable(Level.FINER)) {
                    theirLog.log(Level.FINER, "Error in parser", re);
                }
                return null;
            }
            cnt += 2; // Continuing point to the firs character after the initial
        // line CRLF
        }
        //cnt += 2; // Continuing point to the firs character after the initial
        // line CRLF
        if (message == null) {
            return null;
        }
        if (cnt < limit && !message.isHeadersComplete()) {
            Header header = null;
            int quoteCnt = 0;
            boolean startToken = true;
            int position = bb.position();
            boolean incrCnt; // Whether the cnt should be incremented when continuing for loop
            for (; cnt < limit;) {
                incrCnt = true; // Default is increment, reset every time.

                if (bs[cnt] == ':' && header == null) {
                    if (cnt - position < 1) {
                        // Line starts with colon. Do not accept
                        theirLog.severe("Line starts with colon, unacceptable");
                        if (errorHandler != null) {
                            errorHandler.handleError(((SipServletRequestImpl) (message)), 400, "Malformed header");
                        }

                        return null;
                    }
                    header = Header.create(bs, position, (cnt - position), message);

                    position = cnt + 1;
                    startToken = true;
                } else if (startToken && (bs[cnt] == ' ' || bs[cnt] == '\t')) {
                    position = cnt + 1;
                } else if (bs[cnt] == '"') {
                    quoteCnt++;
                } else if (bs[cnt] == ',' && quoteCnt % 2 == 0 && header != null) { // multi header on one line
                    // header.setInLineValues(true);
                    // Must check if Date header
                    if (!Header.isSingleLineHeader(header) && !((cnt - position) == 3 && cnt + 1 < limit && bs[cnt + 1] == ' ')) {
                        // TODO - Should we throw a parse exception if in single
                        // line
                        // header map?
                        // This will have an impact on performance so it has to
                        // be
                        // measured.
                        // Eg trap Unsupported op ex and generate parse ex.
                        try {
                            header.setValue(
                                    new String(bs, position, (cnt - position), SipFactoryImpl.SIP_CHARSET),
                                    false);
                        } catch (UnsupportedEncodingException e) {
                            throw new ParserException("Failed setting header value", e);
                        }
                        header.setIsNextValueOnSameLine(true, false);
                        position = ++cnt;
                        // Trim WS
                        while (cnt < limit && bs[cnt] == ' ') {
                            position = ++cnt;
                        }
                        if (Header.isSingleLineHeader(header) && theirLog.isLoggable(Level.FINER)) {
                            theirLog.log(Level.FINER, "SingleLineHeader " + header.getName() + " is parsed as multiline header with a separator \',\' ");
                            if (theirLog.isLoggable(Level.FINEST)) {
                                theirLog.log(Level.FINEST, "The SingleLineHeader value : " + header.getValue() + " will be overwritten!");
                            }
                        }
                    }
                } else if ((cnt + 1) < limit && bs[cnt] == '\r' && bs[cnt + 1] == '\n') {
                    if (header == null) {
                        message.setHeadersComplete(true);
                        cnt += 2;
                        // MARK
                        bb.position((cnt > limit) ? limit : cnt);
                        break;
                    } else if (cnt + 3 < limit && bs[cnt + 2] == '\r' && bs[cnt + 3] == '\n') {
                        // The rest is body
                        try {
                            header.setValue(
                                    new String(bs, position, (cnt - position), SipFactoryImpl.SIP_CHARSET),
                                    false);
                        } catch (UnsupportedEncodingException e) {
                            throw new ParserException("Failed setting header value", e);
                        }
                        header.setIsNextValueOnSameLine(false, false);
                        message.addHeader(header);
                        message.setHeadersComplete(true);
                        cnt += 4;
                        // MARK
                        bb.position((cnt > limit) ? limit : cnt);
                        if (theirLog.isLoggable(Level.FINE)) {
                            if (Header.isSingleLineHeader(header)) {
                                theirLog.log(Level.FINE, "Adding Header " + header.getName() + " = " + header.getValue() + " (" + bb.position() + ')');
                            } else {
                                ListIterator<String> li = header.getValues();
                                int x = 0;
                                while (li.hasNext()) {
                                    theirLog.log(Level.FINE, "Adding Header " + header.getName() + " = " + li.next() + " (" + bb.position() + ')' + '<' + (++x) + '>');
                                }
                            }
                        }
                        break;
                    } else if (cnt + 2 < limit && (bs[cnt + 2] == ' ' || bs[cnt + 2] == '\t')) {
                        // Append String - multi line header
                        bs[cnt] = ' ';
                        bs[cnt + 1] = ' ';
                        bs[cnt + 2] = ' ';
                        cnt += 3;
                    } else {
                        try {
                            header.setValue(
                                    new String(bs, position, (cnt - position), SipFactoryImpl.SIP_CHARSET),
                                    false);
                        } catch (UnsupportedEncodingException e) {
                            throw new ParserException("Failed setting header value", e);
                        }
                        header.setIsNextValueOnSameLine(false, false);
                        message.addHeader(header);
                        cnt += 2;
                        // MARK
                        bb.position((cnt > limit) ? limit : cnt);
                        if (theirLog.isLoggable(Level.FINE)) {
                            if (Header.isSingleLineHeader(header)) {
                                theirLog.log(Level.FINE, "Adding Header " + header.getName() + " = " + header.getValue() + " (" + bb.position() + ')');
                            } else {
                                ListIterator<String> li = header.getValues();
                                int x = 0;
                                while (li.hasNext()) {
                                    theirLog.log(Level.FINE, "Adding Header " + header.getName() + " = " + li.next() + " (" + bb.position() + ')' + '<' + (++x) + '>');
                                }
                            }
                        }
                        header = null;
                        quoteCnt = 0;
                        startToken = true;
                        // Don't increment as we have already stepped forward.
                        incrCnt = false;
                    }
                    position = cnt;
                } else if (startToken) {
                    startToken = false;
                }

                // Do the increment if we should.
                if (incrCnt) {
                    cnt++;
                }
            }
        }
        if (message.isHeadersComplete() && !message.isMessageComplete()) {
            String errorStr = null;
            Header header = message.getRawHeader(Header.CALL_ID);
            if (header == null || header.getValue() == null || header.getValue().length() == 0) {
                errorStr = "Failed to validate mandatory header CallId";
            }
            header = message.getRawHeader(Header.TO);
            if (header == null || header.getValue() == null || header.getValue().length() == 0) {
                errorStr = "Failed to validate mandatory header To";
            }
            header = message.getRawHeader(Header.FROM);
            if (header == null || header.getValue() == null || header.getValue().length() == 0) {
                errorStr = "Failed to validate mandatory header From";
            }
            header = message.getRawHeader(Header.CSEQ);
            if (header == null || header.getValue() == null || header.getValue().length() == 0) {
                errorStr = "Failed to validate mandatory header Cseq";
            }
            header = message.getRawHeader(Header.VIA);
            if (header == null || header.getValue() == null || header.getValue().length() == 0) {
                errorStr = "Failed to validate mandatory header Via";
            }
            header = message.getRawHeader(Header.MAX_FORWARDS);
            if ((header == null || header.getValue() == null) && message instanceof SipServletRequestImpl) {
                Header mf = Header.createFormated(Header.MAX_FORWARDS, message);
                mf.setValue("70", false);
                message.setHeader(mf);
                if (theirLog.isLoggable(Level.FINER)) {
                    theirLog.log(Level.FINER, "Added Max-Forwards = " + 70);
                }
            }

            for (MandatoryHeaderValidator validator : mandatoryHeaderValidators) {
                if (!validator.validate(message)) {
                    errorStr = "Failed to parse mandatory header \'" + validator.getHeaderName() + "\'";
                    if (errorHandler != null) {
                        errorHandler.handleError(((SipServletRequestImpl) (message)), 400, errorStr);
                    }
                    theirLog.severe("failed to parse mandatory header " + validator.getHeaderName());
                    return null;
                }
            }
            // validate mandatory header Max-Forwards";
            // TODO - Create max fw = 70 maybe not here
            if (errorStr != null) {
                if (theirLog.isLoggable(Level.FINE)) {
                    theirLog.log(Level.FINE, errorStr + " \r\n" + message);
                }
                return null;
            }
            if (theirLog.isLoggable(Level.FINE)) {
                endTime = System.nanoTime();
                theirLog.log(Level.FINE, "Headers = " + (endTime - startTime) / 1000 + "microsecs");
            }
            int contentLength = message.getContentLengthHeader();
            if (contentLength < 0) { // No Content-Length
                if (message.getRemote().getProtocol() == SipTransports.UDP_PROT) {
                    contentLength = bb.remaining();
                    if (theirLog.isLoggable(Level.FINE)) {
                        theirLog.log(Level.FINE, "Assigning missing Content-Length");
                    }
                    // decision by stoffe to insert Content-Length header if not
                    // previously present
                    message.internalSetContentLength(contentLength);
                } else {
                    if (theirLog.isLoggable(Level.FINE)) {
                        theirLog.log(Level.FINE, "Content length is mandatory for TCP!");
                    }
                    return null;
                }
            }
            boolean contentComplete = false;
            if (contentLength == 0) {
                contentComplete = true;
            }
            if (contentComplete == false) {
                int position = bb.position();
                int remaining = bb.remaining();
                int bytesToCopy;
                int remainingContent = (contentLength - message.getContentOffset());
                if (remainingContent < remaining) {
                    bytesToCopy = remainingContent;
                } else {
                    bytesToCopy = remaining;
                }
                if (bytesToCopy > 0) {
                    if (theirLog.isLoggable(Level.FINE)) {
                        theirLog.log(Level.FINE, "Copy content bytes:" + bytesToCopy);
                    }
                    message.addContent(bs, position, bytesToCopy);
                    remainingContent = (contentLength - message.getContentOffset());
                    if (remainingContent == 0) {
                        contentComplete = true;
                    }
                    if (theirLog.isLoggable(Level.FINE)) {
                        if (remainingContent != 0) {
                            theirLog.log(Level.FINE, "Content remaining after this chunk:" + remainingContent);
                        }
                    }
                    bb.position(position + bytesToCopy);
                }
            }
            if (contentComplete) {
                if (theirLog.isLoggable(Level.FINE)) {
                    theirLog.log(Level.FINE, "Message content is complete. --> Message is complete took : ");
                }
                message.setMessageComplete(true);
                if (theirLog.isLoggable(Level.FINE)) {
                    endTime = System.nanoTime();
                    theirLog.log(Level.FINE, "Total = " + (endTime - startTime) / 1000 + "microsecs");
                }
            }
        }
        SipMessage result = isRequest ? new SipRequest() : (isResponse ? new SipResponse() : null);
        result.setImpl(message);
        return result;
    }
}
TOP

Related Classes of org.jvnet.glassfish.comms.sipagent.model.MySipParser

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.