710 lines
25 KiB
Java
710 lines
25 KiB
Java
/*
|
|
* Conditions Of Use
|
|
*
|
|
* This software was developed by employees of the National Institute of
|
|
* Standards and Technology (NIST), an agency of the Federal Government.
|
|
* Pursuant to title 15 Untied States Code Section 105, works of NIST
|
|
* employees are not subject to copyright protection in the United States
|
|
* and are considered to be in the public domain. As a result, a formal
|
|
* license is not needed to use the software.
|
|
*
|
|
* This software is provided by NIST as a service and is expressly
|
|
* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
|
|
* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
|
|
* AND DATA ACCURACY. NIST does not warrant or make any representations
|
|
* regarding the use of the software or the results thereof, including but
|
|
* not limited to the correctness, accuracy, reliability or usefulness of
|
|
* the software.
|
|
*
|
|
* Permission to use this software is contingent upon your acceptance
|
|
* of the terms of this agreement
|
|
*
|
|
* .
|
|
*
|
|
*/
|
|
|
|
/*******************************************************************************
|
|
* Product of NIST/ITL Advanced Networking Technologies Division (ANTD) *
|
|
******************************************************************************/
|
|
|
|
package gov.nist.javax.sip.parser;
|
|
|
|
import gov.nist.core.Host;
|
|
import gov.nist.core.HostNameParser;
|
|
import gov.nist.javax.sip.SIPConstants;
|
|
import gov.nist.javax.sip.address.AddressImpl;
|
|
import gov.nist.javax.sip.address.GenericURI;
|
|
import gov.nist.javax.sip.address.SipUri;
|
|
import gov.nist.javax.sip.address.TelephoneNumber;
|
|
import gov.nist.javax.sip.header.*;
|
|
import gov.nist.javax.sip.message.SIPMessage;
|
|
import gov.nist.javax.sip.message.SIPRequest;
|
|
import gov.nist.javax.sip.message.SIPResponse;
|
|
|
|
import java.io.UnsupportedEncodingException;
|
|
import java.text.ParseException;
|
|
/*
|
|
* Acknowledgement: 1/12/2007: Yanick Belanger rewrote the parsing loops to make them
|
|
* simpler and quicker.
|
|
*/
|
|
|
|
/**
|
|
* 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.26 $ $Date: 2009/10/22 10:27:38 $
|
|
*
|
|
* @author M. Ranganathan <br/>
|
|
*
|
|
*
|
|
*/
|
|
public class StringMsgParser {
|
|
|
|
protected boolean readBody;
|
|
private ParseExceptionListener parseExceptionListener;
|
|
private String rawStringMessage;
|
|
private boolean strict;
|
|
|
|
private static boolean computeContentLengthFromMessage = false;
|
|
|
|
/**
|
|
* @since v0.9
|
|
*/
|
|
public StringMsgParser() {
|
|
super();
|
|
readBody = true;
|
|
}
|
|
|
|
/**
|
|
* Constructor (given a parse exception handler).
|
|
*
|
|
* @since 1.0
|
|
* @param exhandler
|
|
* is the parse exception listener for the message parser.
|
|
*/
|
|
public StringMsgParser(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) 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.
|
|
String currentLine = null;
|
|
String currentHeader = null;
|
|
boolean isFirstLine = true;
|
|
SIPMessage message = null;
|
|
do
|
|
{
|
|
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;
|
|
|
|
// Make it a String.
|
|
try {
|
|
currentLine = new String(msgBuffer, lineStart, lineLength, "UTF-8");
|
|
} catch (UnsupportedEncodingException e) {
|
|
throw new ParseException("Bad message encoding!", 0);
|
|
}
|
|
|
|
currentLine = trimEndOfLine(currentLine);
|
|
|
|
if (currentLine.length() == 0) {
|
|
// Last header line, process the previous buffered header.
|
|
if (currentHeader != null && message != null) {
|
|
processHeader(currentHeader, message);
|
|
}
|
|
|
|
}
|
|
else {
|
|
if (isFirstLine) {
|
|
message = processFirstLine(currentLine);
|
|
} else {
|
|
char firstChar = currentLine.charAt(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);
|
|
}
|
|
else {
|
|
if (currentHeader != null && message != null) {
|
|
processHeader(currentHeader, message);
|
|
}
|
|
currentHeader = currentLine;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (msgBuffer[i] == '\r' && msgBuffer.length > i+1 && msgBuffer[i+1] == '\n')
|
|
i++;
|
|
|
|
i++;
|
|
|
|
isFirstLine = false;
|
|
} while (currentLine.length() > 0); // End do - while
|
|
|
|
if (message == null) throw new ParseException("Bad message", 0);
|
|
message.setSize(i);
|
|
|
|
if (readBody && message.getContentLength() != null &&
|
|
message.getContentLength().getContentLength() != 0) {
|
|
|
|
int bodyLength = msgBuffer.length - i;
|
|
|
|
byte[] body = new byte[bodyLength];
|
|
System.arraycopy(msgBuffer, i, body, 0, bodyLength);
|
|
message.setMessageContent(body,computeContentLengthFromMessage ,message.getContentLength().getContentLength() );
|
|
}
|
|
|
|
return message;
|
|
}
|
|
|
|
/**
|
|
* Parse a buffer containing one or more SIP Messages and return an array of
|
|
* SIPMessage parsed structures.
|
|
*
|
|
* @param msgString
|
|
* a String 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(String msgString) throws ParseException {
|
|
if (msgString == null || msgString.length() == 0)
|
|
return null;
|
|
|
|
rawStringMessage = msgString;
|
|
|
|
int i = 0;
|
|
|
|
// Squeeze out any leading control character.
|
|
try {
|
|
while (msgString.charAt(i) < 0x20)
|
|
i++;
|
|
}
|
|
catch (ArrayIndexOutOfBoundsException e) {
|
|
// Array contains only control char, return null.
|
|
return null;
|
|
} catch (StringIndexOutOfBoundsException ex) {
|
|
return null;
|
|
}
|
|
|
|
// Iterate thru the request/status line and headers.
|
|
String currentLine = null;
|
|
String currentHeader = null;
|
|
boolean isFirstLine = true;
|
|
SIPMessage message = null;
|
|
do
|
|
{
|
|
int lineStart = i;
|
|
|
|
// Find the length of the line.
|
|
try {
|
|
char c = msgString.charAt(i);
|
|
while (c != '\r' && c != '\n')
|
|
c = msgString.charAt(++i);
|
|
}
|
|
catch (ArrayIndexOutOfBoundsException e) {
|
|
// End of the message.
|
|
break;
|
|
} catch ( StringIndexOutOfBoundsException ex) {
|
|
break;
|
|
}
|
|
|
|
// Make it a String.
|
|
currentLine = msgString.substring(lineStart, i);
|
|
currentLine = trimEndOfLine(currentLine);
|
|
|
|
if (currentLine.length() == 0) {
|
|
// Last header line, process the previous buffered header.
|
|
if (currentHeader != null) {
|
|
processHeader(currentHeader, message);
|
|
}
|
|
}
|
|
else {
|
|
if (isFirstLine) {
|
|
message = processFirstLine(currentLine);
|
|
} else {
|
|
char firstChar = currentLine.charAt(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);
|
|
}
|
|
else {
|
|
if (currentHeader != null) {
|
|
processHeader(currentHeader, message);
|
|
}
|
|
currentHeader = currentLine;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (msgString.charAt(i) == '\r' && msgString.length() > i+1 && msgString.charAt(i+1) == '\n')
|
|
i++;
|
|
|
|
i++;
|
|
|
|
isFirstLine = false;
|
|
}
|
|
while (currentLine.length() > 0);
|
|
|
|
message.setSize(i);
|
|
|
|
// Check for content legth header
|
|
if (readBody && message.getContentLength() != null ) {
|
|
if ( message.getContentLength().getContentLength() != 0) {
|
|
String body = msgString.substring(i);
|
|
message.setMessageContent(body,this.strict,computeContentLengthFromMessage,message.getContentLength().getContentLength());
|
|
} else if (!computeContentLengthFromMessage && message.getContentLength().getContentLength() == 0 && !msgString.endsWith("\r\n\r\n") ){
|
|
if ( strict ) {
|
|
throw new ParseException("Extraneous characters at the end of the message ",i);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return message;
|
|
}
|
|
|
|
private String trimEndOfLine(String line) {
|
|
if (line == null)
|
|
return line;
|
|
|
|
int i = line.length() - 1;
|
|
while (i >= 0 && line.charAt(i) <= 0x20)
|
|
i--;
|
|
|
|
if (i == line.length() - 1)
|
|
return line;
|
|
|
|
if (i == -1)
|
|
return "";
|
|
|
|
return line.substring(0, i+1);
|
|
}
|
|
|
|
private SIPMessage processFirstLine(String firstLine) throws ParseException {
|
|
SIPMessage message;
|
|
if (!firstLine.startsWith(SIPConstants.SIP_VERSION_STRING)) {
|
|
message = new SIPRequest();
|
|
try {
|
|
RequestLine requestLine = new RequestLineParser(firstLine + "\n")
|
|
.parse();
|
|
((SIPRequest) message).setRequestLine(requestLine);
|
|
} catch (ParseException ex) {
|
|
if (this.parseExceptionListener != null)
|
|
this.parseExceptionListener.handleException(ex, message,
|
|
RequestLine.class, firstLine, rawStringMessage);
|
|
else
|
|
throw ex;
|
|
|
|
}
|
|
} else {
|
|
message = new SIPResponse();
|
|
try {
|
|
StatusLine sl = new StatusLineParser(firstLine + "\n").parse();
|
|
((SIPResponse) message).setStatusLine(sl);
|
|
} catch (ParseException ex) {
|
|
if (this.parseExceptionListener != null) {
|
|
this.parseExceptionListener.handleException(ex, message,
|
|
StatusLine.class, firstLine, rawStringMessage);
|
|
} else
|
|
throw ex;
|
|
|
|
}
|
|
}
|
|
return message;
|
|
}
|
|
|
|
private void processHeader(String header, SIPMessage message) throws ParseException {
|
|
if (header == null || header.length() == 0)
|
|
return;
|
|
|
|
HeaderParser headerParser = null;
|
|
try {
|
|
headerParser = ParserFactory.createParser(header + "\n");
|
|
} catch (ParseException ex) {
|
|
this.parseExceptionListener.handleException(ex, message, null,
|
|
header, rawStringMessage);
|
|
return;
|
|
}
|
|
|
|
try {
|
|
SIPHeader sipHeader = headerParser.parse();
|
|
message.attachHeader(sipHeader, false);
|
|
} catch (ParseException ex) {
|
|
if (this.parseExceptionListener != null) {
|
|
String headerName = Lexer.getHeaderName(header);
|
|
Class headerClass = NameMap.getClassFromName(headerName);
|
|
if (headerClass == null) {
|
|
headerClass = ExtensionHeaderImpl.class;
|
|
|
|
}
|
|
this.parseExceptionListener.handleException(ex, message,
|
|
headerClass, header, rawStringMessage);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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(String 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(String 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(String 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(String 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(String 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 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);
|
|
}
|
|
|
|
StringBuffer buffer = new StringBuffer(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.toString());
|
|
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(String requestLine)
|
|
throws ParseException {
|
|
requestLine += "\n";
|
|
return new RequestLineParser(requestLine).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(String statusLine)
|
|
throws ParseException {
|
|
statusLine += "\n";
|
|
return new StatusLineParser(statusLine).parse();
|
|
}
|
|
|
|
public static void setComputeContentLengthFromMessage(
|
|
boolean computeContentLengthFromMessage) {
|
|
StringMsgParser.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\" <sip:LittleGuy@there.com>;tag=469bc066\r\n"
|
|
+ "From: \"The Master Blaster\" <sip:BigGuy@here.com>;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: <sip:172.16.11.162:5070>\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\" <sip:0440@212.209.220.131>;tag=2600\r\n"
|
|
+ "From: \"Andreas\" <sip:andreas@e-horizon.se>;tag=8524\r\n"
|
|
+ "Call-ID: f51a1851c5f570606140f14c8eb64fd3@172.18.1.29\r\n"
|
|
+ "CSeq: 1 INVITE\r\n" + "Max-Forwards: 70\r\n"
|
|
+ "Record-Route: <sip:212.209.220.131:5060>\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: <sip:mranga@nist.gov>;tag=6fcd5c7ace8b4a45acf0f0cd539b168b;epid=0d4c418ddf\r\n"
|
|
+ "To: <sip:mranga@nist.gov>\r\n"
|
|
+ "Call-ID: c5679907eb954a8da9f9dceb282d7230@129.6.55.182\r\n"
|
|
+ "CSeq: 1 REGISTER\r\n"
|
|
+ "Contact: <sip:129.6.55.182:14826>;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:littleguy@there.com:5060 SIP/2.0\r\n"
|
|
+ "Via: SIP/2.0/UDP 65.243.118.100:5050\r\n"
|
|
+ "From: M. Ranganathan <sip:M.Ranganathan@sipbakeoff.com>;tag=1234\r\n"
|
|
+ "To: \"littleguy@there.com\" <sip:littleguy@there.com:5060> \r\n"
|
|
+ "Call-ID: Q2AboBsaGn9!?x6@sipbakeoff.com \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++) {
|
|
StringMsgParser smp = new StringMsgParser();
|
|
try {
|
|
SIPMessage sipMessage = smp
|
|
.parseSIPMessage(messages[i]);
|
|
System.out.println(" i = " + i + " branchId = "
|
|
+ sipMessage.getTopmostVia().getBranch());
|
|
// System.out.println("encoded " +
|
|
// sipMessage.toString());
|
|
} catch (ParseException ex) {
|
|
|
|
}
|
|
|
|
// System.out.println("dialog id = " +
|
|
// sipMessage.getDialogId(false));
|
|
}
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < 20; i++) {
|
|
new Thread(new ParserThread(messages)).start();
|
|
}
|
|
|
|
}
|
|
|
|
public void setStrict(boolean strict) {
|
|
this.strict = strict;
|
|
|
|
}
|
|
|
|
}
|