All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gov.nist.javax.sip.parser.chars.CharsMsgParser Maven / Gradle / Ivy

The newest version!
/*
 * JBoss, Home of Professional Open Source
 * Copyright 2011, Red Hat, Inc. and individual contributors
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */

/*******************************************************************************
 * Product of NIST/ITL Advanced Networking Technologies Division (ANTD)        *
 ******************************************************************************/

package android.gov.nist.javax.sip.parser.chars;

import android.gov.nist.core.Host;
import android.gov.nist.javax.sip.SIPConstants;
import android.gov.nist.javax.sip.address.AddressImpl;
import android.gov.nist.javax.sip.address.GenericURI;
import android.gov.nist.javax.sip.address.SipUri;
import android.gov.nist.javax.sip.address.TelephoneNumber;
import android.gov.nist.javax.sip.header.ExtensionHeaderImpl;
import android.gov.nist.javax.sip.header.NameMap;
import android.gov.nist.javax.sip.header.RequestLine;
import android.gov.nist.javax.sip.header.SIPHeader;
import android.gov.nist.javax.sip.header.StatusLine;
import android.gov.nist.javax.sip.message.SIPMessage;
import android.gov.nist.javax.sip.message.SIPRequest;
import android.gov.nist.javax.sip.message.SIPResponse;
import android.gov.nist.javax.sip.parser.MessageParser;
import android.gov.nist.javax.sip.parser.ParseExceptionListener;

import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.text.ParseException;
import java.util.Arrays;

/**
 * Parse SIP message and parts of SIP messages such as URI's etc from memory and
 * return a structure. Intended use: UDP message processing. This class is used
 * when you have an entire SIP message or SIPHeader or SIP URL in memory and you
 * want to generate a parsed structure from it. For SIP messages, the payload
 * can be binary or String. If you have a binary payload, use
 * parseSIPMessage(byte[]) else use parseSIPMessage(String) The payload is
 * accessible from the parsed message using the getContent and getContentBytes
 * methods provided by the SIPMessage class. If SDP parsing is enabled using the
 * parseContent method, then the SDP body is also parsed and can be accessed
 * from the message using the getSDPAnnounce method. Currently only eager
 * parsing of the message is supported (i.e. the entire message is parsed in one
 * feld swoop).
 *
 *
 * @version 1.2 $Revision: 1.27 $ $Date: 2010/03/15 17:01:21 $
 *
 * @author M. Ranganathan 
* * */ public class CharsMsgParser implements MessageParser { // protected boolean readBody; // protected ParseExceptionListener parseExceptionListener; // protected String rawStringMessage; // protected boolean strict; protected static boolean computeContentLengthFromMessage = false; protected static final Charset charset = Charset.forName("UTF-8"); protected static final char[] SIP_VERSION_CHAR = SIPConstants.SIP_VERSION_STRING.toCharArray(); /** * @since v0.9 */ public CharsMsgParser() { super(); // readBody = true; } // /** // * Constructor (given a parse exception handler). // * // * @since 1.0 // * @param exhandler // * is the parse exception listener for the message parser. // */ // public CharsMsgParser(ParseExceptionListener exhandler) { // this(); // parseExceptionListener = exhandler; // } // // /** // * Add a handler for header parsing errors. // * // * @param pexhandler // * is a class that implements the ParseExceptionListener // * interface. // */ // public void setParseExceptionListener(ParseExceptionListener pexhandler) { // parseExceptionListener = pexhandler; // } /** * Parse a buffer containing a single SIP Message where the body is an array * of un-interpreted bytes. This is intended for parsing the message from a * memory buffer when the buffer. Incorporates a bug fix for a bug that was * noted by Will Sullin of Callcast * * @param msgBuffer * a byte buffer containing the messages to be parsed. This can * consist of multiple SIP Messages concatenated together. * @return a SIPMessage[] structure (request or response) containing the * parsed SIP message. * @exception ParseException * is thrown when an illegal message has been encountered * (and the rest of the buffer is discarded). * @see ParseExceptionListener */ public SIPMessage parseSIPMessage(byte[] msgBuffer, boolean readBody, boolean strict, ParseExceptionListener exhandler) throws ParseException { if (msgBuffer == null || msgBuffer.length == 0) return null; int i = 0; // Squeeze out any leading control character. try { while (msgBuffer[i] < 0x20) i++; } catch (ArrayIndexOutOfBoundsException e) { // Array contains only control char, return null. return null; } // Iterate thru the request/status line and headers. char[] currentLine = null; char[] currentHeader = null; boolean isFirstLine = true; SIPMessage message = null; do { currentLine = null; int lineStart = i; // Find the length of the line. try { while (msgBuffer[i] != '\r' && msgBuffer[i] != '\n') i++; } catch (ArrayIndexOutOfBoundsException e) { // End of the message. break; } int lineLength = i - lineStart; ByteBuffer bb = ByteBuffer.wrap(msgBuffer, lineStart, lineLength); currentLine = charset.decode(bb).array(); currentLine = trimEndOfLine(currentLine); if (currentLine.length == 0) { // Last header line, process the previous buffered header. if (currentHeader != null && message != null) { processHeader(currentHeader, message, exhandler, msgBuffer); } } else { if (isFirstLine) { message = processFirstLine(currentLine, exhandler, msgBuffer); } else { char firstChar = currentLine[0]; if (firstChar == '\t' || firstChar == ' ') { if (currentHeader == null) throw new ParseException("Bad header continuation.", 0); //This is a continuation, append it to the previous line. // currentHeader += currentLine.substring(1); char[] retval = new char[currentHeader.length + currentLine.length - 1]; System.arraycopy(currentHeader, 0, retval, 0, currentHeader.length); System.arraycopy(currentHeader, currentHeader.length, currentLine, 1, currentLine.length); } else { if (currentHeader != null && message != null) { processHeader(currentHeader, message, exhandler, msgBuffer); } currentHeader = new char[currentLine.length + 1]; System.arraycopy(currentLine, 0, currentHeader, 0, currentLine.length); currentHeader[currentLine.length] = '\n'; } } } if (msgBuffer[i] == '\r' && msgBuffer.length > i+1 && msgBuffer[i+1] == '\n') i++; i++; isFirstLine = false; } while (currentLine.length > 0); // End do - while currentLine = null; currentHeader = null; if (message == null) throw new ParseException("Bad message", 0); message.setSize(i); // Check for content legth header if (readBody && message.getContentLength() != null ) { if ( message.getContentLength().getContentLength() != 0) { int bodyLength = msgBuffer.length - i; byte[] body = new byte[bodyLength]; System.arraycopy(msgBuffer, i, body, 0, bodyLength); message.setMessageContent(body,!strict,computeContentLengthFromMessage,message.getContentLength().getContentLength()); } else if (!computeContentLengthFromMessage && message.getContentLength().getContentLength() == 0 & strict) { String last4Chars = new String(msgBuffer, msgBuffer.length - 4, 4); if(!"\r\n\r\n".equals(last4Chars)) { throw new ParseException("Extraneous characters at the end of the message ",i); } } } return message; } protected static char[] trimEndOfLine(char[] line) { if (line == null) return line; int i = line.length - 1; while (i >= 0 && line[i] <= 0x20) i--; if (i == line.length - 1) return line; if (i == -1) return "".intern().toCharArray(); char[] retval = new char[i+1]; System.arraycopy(line, 0, retval, 0, i+1); return retval; } protected SIPMessage processFirstLine(char[] firstLine, ParseExceptionListener parseExceptionListener, byte[] msgBuffer) throws ParseException { SIPMessage message; char[] retval = new char[firstLine.length + 1]; System.arraycopy(firstLine, 0, retval, 0, firstLine.length); retval[firstLine.length] = '\n'; char[] sipVersionCompare = new char[7]; System.arraycopy(firstLine, 0, sipVersionCompare, 0, 7); if (!Arrays.equals(sipVersionCompare, SIP_VERSION_CHAR)) { message = new SIPRequest(); try { RequestLine requestLine = new RequestLineParser(retval) .parse(); ((SIPRequest) message).setRequestLine(requestLine); } catch (ParseException ex) { if (parseExceptionListener != null) parseExceptionListener.handleException(ex, message, RequestLine.class, String.valueOf(firstLine), String.valueOf(msgBuffer)); else throw ex; } } else { message = new SIPResponse(); try { StatusLine sl = new StatusLineParser(retval).parse(); ((SIPResponse) message).setStatusLine(sl); } catch (ParseException ex) { if (parseExceptionListener != null) { parseExceptionListener.handleException(ex, message, StatusLine.class, String.valueOf(firstLine), String.valueOf(msgBuffer)); } else throw ex; } } return message; } protected void processHeader(char[] header, SIPMessage message, ParseExceptionListener parseExceptionListener, byte[] msgBuffer) throws ParseException { if (header == null || header.length == 0) return; HeaderParser headerParser = null; try { headerParser = ParserFactory.createParser(header); } catch (ParseException ex) { parseExceptionListener.handleException(ex, message, null, String.valueOf(header), String.valueOf(msgBuffer)); return; } try { SIPHeader sipHeader = headerParser.parse(); message.attachHeader(sipHeader, false); } catch (ParseException ex) { if (parseExceptionListener != null) { String headerName = Lexer.getHeaderName(header); Class headerClass = NameMap.getClassFromName(headerName); if (headerClass == null) { headerClass = ExtensionHeaderImpl.class; } parseExceptionListener.handleException(ex, message, headerClass, String.valueOf(header), String.valueOf(msgBuffer)); } } } /** * Parse an address (nameaddr or address spec) and return and address * structure. * * @param address * is a String containing the address to be parsed. * @return a parsed address structure. * @since v1.0 * @exception ParseException * when the address is badly formatted. */ public AddressImpl parseAddress(char[] address) throws ParseException { AddressParser addressParser = new AddressParser(address); return addressParser.address(true); } /** * Parse a host:port and return a parsed structure. * * @param hostport * is a String containing the host:port to be parsed * @return a parsed address structure. * @since v1.0 * @exception throws * a ParseException when the address is badly formatted. * public HostPort parseHostPort(String hostport) throws ParseException { Lexer lexer = new Lexer("charLexer", hostport); return new HostNameParser(lexer).hostPort(); } */ /** * Parse a host name and return a parsed structure. * * @param host * is a String containing the host name to be parsed * @return a parsed address structure. * @since v1.0 * @exception ParseException * a ParseException when the hostname is badly formatted. */ public Host parseHost(char[] host) throws ParseException { Lexer lexer = new Lexer("charLexer", host); return new HostNameParser(lexer).host(); } /** * Parse a telephone number return a parsed structure. * * @param telephone_number * is a String containing the telephone # to be parsed * @return a parsed address structure. * @since v1.0 * @exception ParseException * a ParseException when the address is badly formatted. */ public TelephoneNumber parseTelephoneNumber(char[] telephone_number) throws ParseException { // Bug fix contributed by Will Scullin return new URLParser(telephone_number).parseTelephoneNumber(true); } /** * Parse a SIP url from a string and return a URI structure for it. * * @param url * a String containing the URI structure to be parsed. * @return A parsed URI structure * @exception ParseException * if there was an error parsing the message. */ public SipUri parseSIPUrl(char[] url) throws ParseException { try { return new URLParser(url).sipURL(true); } catch (ClassCastException ex) { throw new ParseException(url + " Not a SIP URL ", 0); } } /** * Parse a uri from a string and return a URI structure for it. * * @param url * a String containing the URI structure to be parsed. * @return A parsed URI structure * @exception ParseException * if there was an error parsing the message. */ public GenericURI parseUrl(char[] url) throws ParseException { return new URLParser(url).parse(); } /** * Parse an individual SIP message header from a string. * * @param header * String containing the SIP header. * @return a SIPHeader structure. * @exception ParseException * if there was an error parsing the message. */ // public static SIPHeader parseSIPHeader(String header) throws ParseException { // int start = 0; // int end = header.length() - 1; // try { // // Squeeze out any leading control character. // while (header.charAt(start) <= 0x20) // start++; // // // Squeeze out any trailing control character. // while (header.charAt(end) <= 0x20) // end--; // } // catch (ArrayIndexOutOfBoundsException e) { // // Array contains only control char. // throw new ParseException("Empty header.", 0); // } // // StringBuilder buffer = new StringBuilder(end + 1); // int i = start; // int lineStart = start; // boolean endOfLine = false; // while (i <= end) { // char c = header.charAt(i); // if (c == '\r' || c == '\n') { // if (!endOfLine) { // buffer.append(header.substring(lineStart, i)); // endOfLine = true; // } // } // else { // if (endOfLine) { // endOfLine = false; // if (c == ' ' || c == '\t') { // buffer.append(' '); // lineStart = i + 1; // } // else { // lineStart = i; // } // } // } // // i++; // } // buffer.append(header.substring(lineStart, i)); // buffer.append('\n'); // // HeaderParser hp = ParserFactory.createParser(buffer); // if (hp == null) // throw new ParseException("could not create parser", 0); // return hp.parse(); // } /** * Parse the SIP Request Line * * @param requestLine * a String containing the request line to be parsed. * @return a RequestLine structure that has the parsed RequestLine * @exception ParseException * if there was an error parsing the requestLine. */ public RequestLine parseSIPRequestLine(char[] requestLine) throws ParseException { // requestLine += "\n"; char[] retval = new char[requestLine.length + 1]; System.arraycopy(requestLine, 0, retval, 0, requestLine.length); retval[requestLine.length] = '\n'; return new RequestLineParser(retval).parse(); } /** * Parse the SIP Response message status line * * @param statusLine * a String containing the Status line to be parsed. * @return StatusLine class corresponding to message * @exception ParseException * if there was an error parsing * @see StatusLine */ public StatusLine parseSIPStatusLine(char[] statusLine) throws ParseException { // statusLine += "\n"; char[] retval = new char[statusLine.length + 1]; System.arraycopy(statusLine, 0, retval, 0, statusLine.length); retval[statusLine.length] = '\n'; return new StatusLineParser(statusLine).parse(); } public static void setComputeContentLengthFromMessage( boolean computeContentLengthFromMessage) { CharsMsgParser.computeContentLengthFromMessage = computeContentLengthFromMessage; } /** * Test code. */ public static void main(String[] args) throws ParseException { String messages[] = { "SIP/2.0 200 OK\r\n" + "To: \"The Little Blister\" ;tag=469bc066\r\n" + "From: \"The Master Blaster\" ;tag=11\r\n" + "Via: SIP/2.0/UDP 139.10.134.246:5060;branch=z9hG4bK8b0a86f6_1030c7d18e0_17;received=139.10.134.246\r\n" + "Call-ID: 1030c7d18ae_a97b0b_b@8b0a86f6\r\n" + "CSeq: 1 SUBSCRIBE\r\n" + "Contact: \r\n" + "Content-Length: 0\r\n\r\n", "SIP/2.0 180 Ringing\r\n" + "Via: SIP/2.0/UDP 172.18.1.29:5060;branch=z9hG4bK43fc10fb4446d55fc5c8f969607991f4\r\n" + "To: \"0440\" ;tag=2600\r\n" + "From: \"Andreas\" ;tag=8524\r\n" + "Call-ID: [email protected]\r\n" + "CSeq: 1 INVITE\r\n" + "Max-Forwards: 70\r\n" + "Record-Route: \r\n" + "Content-Length: 0\r\n\r\n", "REGISTER sip:nist.gov SIP/2.0\r\n" + "Via: SIP/2.0/UDP 129.6.55.182:14826\r\n" + "Max-Forwards: 70\r\n" + "From: ;tag=6fcd5c7ace8b4a45acf0f0cd539b168b;epid=0d4c418ddf\r\n" + "To: \r\n" + "Call-ID: [email protected]\r\n" + "CSeq: 1 REGISTER\r\n" + "Contact: ;methods=\"INVITE, MESSAGE, INFO, SUBSCRIBE, OPTIONS, BYE, CANCEL, NOTIFY, ACK, REFER\"\r\n" + "User-Agent: RTC/(Microsoft RTC)\r\n" + "Event: registration\r\n" + "Allow-Events: presence\r\n" + "Content-Length: 0\r\n\r\n" + "INVITE sip:[email protected]:5060 SIP/2.0\r\n" + "Via: SIP/2.0/UDP 65.243.118.100:5050\r\n" + "From: M. Ranganathan ;tag=1234\r\n" + "To: \"[email protected]\" \r\n" + "Call-ID: [email protected] \r\n" + "CSeq: 1 INVITE \r\n" + "Content-Length: 247\r\n\r\n" + "v=0\r\n" + "o=4855 13760799956958020 13760799956958020 IN IP4 129.6.55.78\r\n" + "s=mysession session\r\n" + "p=+46 8 52018010\r\n" + "c=IN IP4 129.6.55.78\r\n" + "t=0 0\r\n" + "m=audio 6022 RTP/AVP 0 4 18\r\n" + "a=rtpmap:0 PCMU/8000\r\n" + "a=rtpmap:4 G723/8000\r\n" + "a=rtpmap:18 G729A/8000\r\n" + "a=ptime:20\r\n" }; class ParserThread implements Runnable { String[] messages; public ParserThread(String[] messagesToParse) { this.messages = messagesToParse; } public void run() { for (int i = 0; i < messages.length; i++) { CharsMsgParser smp = new CharsMsgParser(); try { SIPMessage sipMessage = smp .parseSIPMessage(messages[i].getBytes(), true, true, null); System.out.println(" i = " + i + " branchId = " + sipMessage.getTopmostVia().getBranch()); // System.out.println("encoded " + // sipMessage.toString()); } catch (ParseException ex) { ex.printStackTrace(); } // System.out.println("dialog id = " + // sipMessage.getDialogId(false)); } } } // for (int i = 0; i < 20; i++) { // new Thread(new ParserThread(messages)).start(); // } new ParserThread(messages).run(); } // public void setStrict(boolean strict) { // this.strict = strict; // // } // // public void setReadBody(boolean readBody) { // this.readBody = readBody; // } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy