gov.nist.javax.sip.parser.PipelinedMsgParser Maven / Gradle / Ivy
/*
* 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;
/*
*
* Lamine Brahimi and Yann Duponchel (IBM Zurich) noticed that the parser was
* blocking so I threw out some cool pipelining which ran fast but only worked
* when the phase of the moon matched its mood. Now things are serialized and
* life goes slower but more reliably.
*
*/
import gov.nist.core.CommonLogger;
import gov.nist.core.InternalErrorHandler;
import gov.nist.core.LogLevels;
import gov.nist.core.LogWriter;
import gov.nist.core.StackLogger;
import gov.nist.javax.sip.header.ContentLength;
import gov.nist.javax.sip.message.SIPMessage;
import gov.nist.javax.sip.stack.BlockingQueueDispatchAuditor;
import gov.nist.javax.sip.stack.ConnectionOrientedMessageChannel;
import gov.nist.javax.sip.stack.QueuedMessageDispatchBase;
import gov.nist.javax.sip.stack.SIPTransactionStack;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.text.ParseException;
import java.util.Queue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.Semaphore;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* This implements a pipelined message parser suitable for use with a stream -
* oriented input such as TCP. The client uses this class by instatiating with
* an input stream from which input is read and fed to a message parser. It
* keeps reading from the input stream and process messages in a never ending
* interpreter loop. The message listener interface gets called for processing
* messages or for processing errors. The payload specified by the
* content-length header is read directly from the input stream. This can be
* accessed from the SIPMessage using the getContent and getContentBytes methods
* provided by the SIPMessage class.
*
* @version 1.2 $Revision: 1.39 $ $Date: 2010-12-02 22:04:22 $
*
* @author M. Ranganathan
*
* @see SIPMessageListener
*/
public final class PipelinedMsgParser implements Runnable {
private static StackLogger logger = CommonLogger.getLogger(PipelinedMsgParser.class);
private static final String CRLF = "\r\n";
/**
* The message listener that is registered with this parser. (The message
* listener has methods that can process correct and erroneous messages.)
*/
protected SIPMessageListener sipMessageListener;
private Thread mythread; // Preprocessor thread
//private byte[] messageBody;
//private boolean errorFlag;
private Pipeline rawInputStream;
private int maxMessageSize;
private int sizeCounter;
private SIPTransactionStack sipStack;
private MessageParser smp = null;
private ConcurrentHashMap messagesOrderingMap = new ConcurrentHashMap();
boolean isRunning = false;
/**
* default constructor.
*/
protected PipelinedMsgParser() {
super();
}
private static int uid = 0;
private static synchronized int getNewUid() {
return uid++;
}
/**
* Constructor when we are given a message listener and an input stream
* (could be a TCP connection or a file)
*
* @param sipMessageListener
* Message listener which has methods that get called back from
* the parser when a parse is complete
* @param in
* Input stream from which to read the input.
* @param debug
* Enable/disable tracing or lexical analyser switch.
*/
public PipelinedMsgParser(SIPTransactionStack sipStack, SIPMessageListener sipMessageListener,
Pipeline in, boolean debug, int maxMessageSize) {
this();
this.sipStack = sipStack;
smp = sipStack.getMessageParserFactory().createMessageParser(sipStack);
this.sipMessageListener = sipMessageListener;
rawInputStream = in;
this.maxMessageSize = maxMessageSize;
mythread = new Thread(this);
mythread.setName("PipelineThread-" + getNewUid());
}
/**
* This is the constructor for the pipelined parser.
*
* @param mhandler
* a SIPMessageListener implementation that provides the message
* handlers to handle correctly and incorrectly parsed messages.
* @param in
* An input stream to read messages from.
*/
public PipelinedMsgParser(SIPTransactionStack sipStack, SIPMessageListener mhandler, Pipeline in,
int maxMsgSize) {
this(sipStack, mhandler, in, false, maxMsgSize);
}
/**
* This is the constructor for the pipelined parser.
*
* @param in -
* An input stream to read messages from.
*/
public PipelinedMsgParser(SIPTransactionStack sipStack, Pipeline in) {
this(sipStack, null, in, false, 0);
}
/**
* Start reading and processing input.
*/
public void processInput() {
mythread.start();
}
/**
* Create a new pipelined parser from an existing one.
*
* @return A new pipelined parser that reads from the same input stream.
*/
protected Object clone() {
PipelinedMsgParser p = new PipelinedMsgParser();
p.rawInputStream = this.rawInputStream;
p.sipMessageListener = this.sipMessageListener;
Thread mythread = new Thread(p);
mythread.setName("PipelineThread");
return p;
}
/**
* Add a class that implements a SIPMessageListener interface whose methods
* get called * on successful parse and error conditons.
*
* @param mlistener
* a SIPMessageListener implementation that can react to correct
* and incorrect pars.
*/
public void setMessageListener(SIPMessageListener mlistener) {
sipMessageListener = mlistener;
}
/**
* read a line of input. Note that we encode the result in UTF-8
*/
private String readLine(InputStream inputStream) throws IOException {
int counter = 0;
int increment = 1024;
int bufferSize = increment;
byte[] lineBuffer = new byte[bufferSize];
// handles RFC 5626 CRLF keepalive mechanism
byte[] crlfBuffer = new byte[2];
int crlfCounter = 0;
while (true) {
char ch;
int i = inputStream.read();
if (i == -1) {
throw new IOException("End of stream");
} else
ch = (char) ( i & 0xFF);
// reduce the available read size by 1 ("size" of a char).
if (this.maxMessageSize > 0) {
this.sizeCounter--;
if (this.sizeCounter <= 0)
throw new IOException("Max size exceeded!");
}
if (ch != '\r')
lineBuffer[counter++] = (byte) (i&0xFF);
else if (counter == 0)
crlfBuffer[crlfCounter++] = (byte) '\r';
if (ch == '\n') {
if(counter == 1 && crlfCounter > 0) {
crlfBuffer[crlfCounter++] = (byte) '\n';
}
break;
}
if( counter == bufferSize ) {
byte[] tempBuffer = new byte[bufferSize + increment];
System.arraycopy((Object)lineBuffer,0, (Object)tempBuffer, 0, bufferSize);
bufferSize = bufferSize + increment;
lineBuffer = tempBuffer;
}
}
if(counter == 1 && crlfCounter > 0) {
return new String(crlfBuffer,0,crlfCounter,"UTF-8");
} else {
return new String(lineBuffer,0,counter,"UTF-8");
}
}
public class Dispatch implements Runnable, QueuedMessageDispatchBase{
CallIDOrderingStructure callIDOrderingStructure;
String callId;
long time;
public Dispatch(CallIDOrderingStructure callIDOrderingStructure, String callId) {
this.callIDOrderingStructure = callIDOrderingStructure;
this.callId = callId;
time = System.currentTimeMillis();
}
public void run() {
// we acquire it in the thread to avoid blocking other messages with a different call id
// that could be processed in parallel
Semaphore semaphore = callIDOrderingStructure.getSemaphore();
final Queue messagesForCallID = callIDOrderingStructure.getMessagesForCallID();
if(sipStack.sipEventInterceptor != null) {
sipStack.sipEventInterceptor.beforeMessage(messagesForCallID.peek());
}
try {
semaphore.acquire();
} catch (InterruptedException e) {
logger.logError("Semaphore acquisition for callId " + callId + " interrupted", e);
}
// once acquired we get the first message to process
SIPMessage message = messagesForCallID.poll();
if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
logger.logDebug("semaphore acquired for message " + message);
}
try {
sipMessageListener.processMessage(message);
} catch (Exception e) {
logger.logError("Error occured processing message", e);
// We do not break the TCP connection because other calls use the same socket here
} finally {
if(messagesForCallID.size() <= 0) {
messagesOrderingMap.remove(callId);
if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
logger.logDebug("CallIDOrderingStructure removed for message " + callId);
}
}
if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
logger.logDebug("releasing semaphore for message " + message);
}
//release the semaphore so that another thread can process another message from the call id queue in the correct order
// or a new message from another call id queue
semaphore.release();
if(messagesOrderingMap.isEmpty()) {
synchronized (messagesOrderingMap) {
messagesOrderingMap.notify();
}
}
if(sipStack.sipEventInterceptor != null) {
sipStack.sipEventInterceptor.afterMessage(message);
}
}
if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
logger.logDebug("dispatch task done on " + message + " threadname " + mythread.getName());
}
}
public long getReceptionTime() {
return time;
}
};
/**
* This is input reading thread for the pipelined parser. You feed it input
* through the input stream (see the constructor) and it calls back an event
* listener interface for message processing or error. It cleans up the
* input - dealing with things like line continuation
*/
public void run() {
Pipeline inputStream = this.rawInputStream;
final StackLogger stackLogger = logger;
// inputStream = new MyFilterInputStream(this.rawInputStream);
// I cannot use buffered reader here because we may need to switch
// encodings to read the message body.
try {
isRunning = true;
while (isRunning) {
this.sizeCounter = this.maxMessageSize;
// this.messageSize = 0;
StringBuilder inputBuffer = new StringBuilder();
if (logger.isLoggingEnabled(LogLevels.TRACE_DEBUG)) {
logger.logDebug("Starting to parse.");
}
String line1;
String line2 = null;
boolean isPreviousLineCRLF = false;
while (true) {
try {
line1 = readLine(inputStream);
// ignore blank lines.
if (line1.equals("\n")) {
if (logger.isLoggingEnabled(LogLevels.TRACE_DEBUG)) {
logger.logDebug("Discarding blank line");
}
continue;
} else if(CRLF.equals(line1)) {
if(isPreviousLineCRLF) {
// Handling keepalive ping (double CRLF) as defined per RFC 5626 Section 4.4.1
// sending pong (single CRLF)
if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
logger.logDebug("KeepAlive Double CRLF received, sending single CRLF as defined per RFC 5626 Section 4.4.1");
logger.logDebug("~~~ setting isPreviousLineCRLF=false");
}
isPreviousLineCRLF = false;
try {
sipMessageListener.sendSingleCLRF();
} catch (Exception e) {
logger.logError("A problem occured while trying to send a single CLRF in response to a double CLRF", e);
}
continue;
} else {
isPreviousLineCRLF = true;
if (logger.isLoggingEnabled(LogLevels.TRACE_DEBUG)) {
logger.logDebug("Received CRLF");
}
if(sipMessageListener != null &&
sipMessageListener instanceof ConnectionOrientedMessageChannel) {
((ConnectionOrientedMessageChannel)sipMessageListener).cancelPingKeepAliveTimeoutTaskIfStarted();
}
}
continue;
} else
break;
} catch (IOException ex) {
// we only wait if the thread is still in a running state and hasn't been close from somewhere else
// or we are leaking because the thread is waiting forever
if(PostParseExecutorServices.getPostParseExecutor() != null && isRunning){
if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
logger.logDebug("waiting for messagesOrderingMap " + this + " threadname " + mythread.getName());
synchronized (messagesOrderingMap) {
try {
messagesOrderingMap.wait(64000);
} catch (InterruptedException e) {}
}
if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
logger.logDebug("got notified for messagesOrderingMap " + this + " threadname " + mythread.getName());
}
this.rawInputStream.stopTimer();
if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
logger.logDebug("thread ending for threadname " + mythread.getName());
}
if (logger.isLoggingEnabled(LogLevels.TRACE_DEBUG)) {
logger.logStackTrace(LogLevels.TRACE_DEBUG);
}
return;
}
}
inputBuffer.append(line1);
// Guard against bad guys.
this.rawInputStream.startTimer();
int bytesRead = 0;
if (logger.isLoggingEnabled(LogLevels.TRACE_DEBUG)) {
logger.logDebug("Reading Input stream.");
}
while (true) {
try {
line2 = readLine(inputStream);
bytesRead += line2.length();
if(maxMessageSize>0 && bytesRead> (maxMessageSize/2) ) throw new IOException("Pre-content-length headers size exceeded. The size of the message of the headers prior to Content-Length is too large. This must be an invalid message. Limit is MAX_MESSAGE_SIZE/2=" + maxMessageSize/2);
inputBuffer.append(line2);
if (line2.trim().equals(""))
break;
} catch (IOException ex) {
// we only wait if the thread is still in a running state and hasn't been close from somewhere else
// or we are leaking because the thread is waiting forever
if(PostParseExecutorServices.getPostParseExecutor() != null && isRunning){
if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
logger.logDebug("waiting for messagesOrderingMap " + this + " threadname " + mythread.getName());
synchronized (messagesOrderingMap) {
try {
messagesOrderingMap.wait(64000);
} catch (InterruptedException e) {}
}
if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
logger.logDebug("got notified for messagesOrderingMap " + this + " threadname " + mythread.getName());
}
this.rawInputStream.stopTimer();
if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
logger.logDebug("thread ending for threadname " + mythread.getName());
}
if (logger.isLoggingEnabled(LogLevels.TRACE_DEBUG)) {
logger.logStackTrace(LogLevels.TRACE_DEBUG);
}
return;
}
}
// Stop the timer that will kill the read.
this.rawInputStream.stopTimer();
inputBuffer.append(line2);
// smp.setParseExceptionListener(sipMessageListener);
// smp.setReadBody(false);
SIPMessage sipMessage = null;
try {
if (stackLogger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
stackLogger.logDebug("About to parse : " + inputBuffer.toString());
}
byte[] inputBufferBytes;
try {
inputBufferBytes = inputBuffer.toString().getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
// fall back to default encoding. The lack of UTF8 support has been logged at SIP stack startup
inputBufferBytes = inputBuffer.toString().getBytes();
}
sipMessage = smp.parseSIPMessage(inputBufferBytes, false, false, sipMessageListener);
if (sipMessage == null) {
this.rawInputStream.stopTimer();
continue;
}
} catch (ParseException ex) {
// Just ignore the parse exception.
if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
logger.logDebug("Detected a parse error", ex);
}
continue;
}
if (logger.isLoggingEnabled(LogLevels.TRACE_DEBUG)) {
logger.logDebug("Completed parsing message");
}
String clString = sipMessage.getHeaderAsFormattedString(ContentLength.NAME);
if(clString.length()>30) throw new RuntimeException("Bad content lenght header " + clString);
ContentLength cl = (ContentLength) sipMessage
.getContentLength();
int contentLength = 0;
if (cl != null) {
contentLength = cl.getContentLength();
} else {
contentLength = 0;
}
if (logger.isLoggingEnabled(LogLevels.TRACE_DEBUG)) {
logger.logDebug("Content length = " + contentLength);
}
if(maxMessageSize > 0 && contentLength > maxMessageSize) throw new RuntimeException("Max content size Exceeded! :" + contentLength + " allowed max size is " + maxMessageSize);
if (contentLength == 0) {
sipMessage.removeContent();
} else if (maxMessageSize == 0
|| contentLength < this.sizeCounter) {
byte[] message_body = new byte[contentLength];
int nread = 0;
while (nread < contentLength) {
// Start my starvation timer.
// This ensures that the other end
// writes at least some data in
// or we will close the pipe from
// him. This prevents DOS attack
// that takes up all our connections.
this.rawInputStream.startTimer();
try {
int readlength = inputStream.read(message_body,
nread, contentLength - nread);
if (readlength > 0) {
nread += readlength;
} else {
break;
}
} catch (IOException ex) {
stackLogger.logError("Exception Reading Content",ex);
break;
} finally {
// Stop my starvation timer.
this.rawInputStream.stopTimer();
}
}
sipMessage.setMessageContent(message_body);
}
// Content length too large - process the message and
// return error from there.
if (sipMessageListener != null) {
try {
if(PostParseExecutorServices.getPostParseExecutor() == null) {
/**
* If gov.nist.javax.sip.TCP_POST_PARSING_THREAD_POOL_SIZE is disabled
* we continue with the old logic here.
*/
if(sipStack.sipEventInterceptor != null) {
sipStack.sipEventInterceptor.beforeMessage(sipMessage);
}
sipMessageListener.processMessage(sipMessage);
if(sipStack.sipEventInterceptor != null) {
sipStack.sipEventInterceptor.afterMessage(sipMessage);
}
} else {
/**
* gov.nist.javax.sip.TCP_POST_PARSING_THREAD_POOL_SIZE is enabled so
* we use the threadpool to execute the task.
*/
// we need to guarantee message ordering on the same socket on TCP
// so we lock and queue of messages per Call Id
final String callId = sipMessage.getCallId().getCallId();
// http://dmy999.com/article/34/correct-use-of-concurrenthashmap
CallIDOrderingStructure orderingStructure = messagesOrderingMap.get(callId);
if(orderingStructure == null) {
CallIDOrderingStructure newCallIDOrderingStructure = new CallIDOrderingStructure();
orderingStructure = messagesOrderingMap.putIfAbsent(callId, newCallIDOrderingStructure);
if(orderingStructure == null) {
orderingStructure = newCallIDOrderingStructure;
if (stackLogger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
stackLogger.logDebug("new CallIDOrderingStructure added for message " + sipMessage);
}
}
}
final CallIDOrderingStructure callIDOrderingStructure = orderingStructure;
// we add the message to the pending queue of messages to be processed for that call id here
// to avoid blocking other messages with a different call id
// that could be processed in parallel
callIDOrderingStructure.getMessagesForCallID().offer(sipMessage);
PostParseExecutorServices.getPostParseExecutor().execute(new Dispatch(callIDOrderingStructure, callId)); // run in executor thread
}
} catch (Exception ex) {
// fatal error in processing - close the
// connection.
break;
}
}
}
} finally {
try {
cleanMessageOrderingMap();
if(!inputStream.isClosed()) {
inputStream.close();
}
} catch (IOException e) {
InternalErrorHandler.handleException(e);
}
}
}
/**
* Data structure to make sure ordering of Messages is guaranteed under TCP when the post parsing thread pool is used
* @author [email protected]
*
*/
class CallIDOrderingStructure {
private Semaphore semaphore;
private Queue messagesForCallID;
public CallIDOrderingStructure() {
semaphore = new Semaphore(1, true);
messagesForCallID = new ConcurrentLinkedQueue();
}
/**
* @return the semaphore
*/
public Semaphore getSemaphore() {
return semaphore;
}
/**
* @return the messagesForCallID
*/
public Queue getMessagesForCallID() {
return messagesForCallID;
}
}
public void close() {
isRunning = false;
if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
logger.logDebug("Closing pipelinedmsgparser " + this + " threadname " + mythread.getName());
try {
this.rawInputStream.close();
} catch (IOException ex) {
if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
logger.logDebug("Couldn't close the rawInputStream " + this + " threadname " + mythread.getName() + " already closed ? " + rawInputStream.isClosed());
// Ignore.
}
if(PostParseExecutorServices.getPostParseExecutor() != null){
cleanMessageOrderingMap();
synchronized (mythread) {
mythread.notifyAll();
//interrupting because there is a race condition on the messagesOrderingMap.wait() that
// eventually leads to thread leaking and OutOfMemory
mythread.interrupt();
}
}
}
private void cleanMessageOrderingMap() {
// not needed and can cause NPE on close if race condition
// for (CallIDOrderingStructure callIDOrderingStructure: messagesOrderingMap.values()) {
// callIDOrderingStructure.getSemaphore().release();
// callIDOrderingStructure.getMessagesForCallID().clear();
// }
messagesOrderingMap.clear();
synchronized (messagesOrderingMap) {
messagesOrderingMap.notifyAll();
}
if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
logger.logDebug("cleaned the messagesOrderingMap " + this + " threadname " + mythread.getName());
}
}
/*
* $Log: not supported by cvs2svn $
* Revision 1.38 2010/12/02 11:44:16 vralev
* Issue number: 346
* Obtained from: vralev
*
* Congestion control. Patch + Tests for HEAD
*
* Revision 1.37 2010/10/26 23:49:12 vralev
* Issue number: 337
* Obtained from: vralev
*
* Revision 1.36 2010/10/13 15:26:59 deruelle_jean
* Fix for TCP calls under load freeze JAIN SIP with TCP_POST_PARSING_THREAD_POOL_SIZE > 0
*
* Issue number:
* Obtained from:
* Submitted by: Jean Deruelle
* Reviewed by:
*
* Revision 1.35 2010/10/12 18:47:16 deruelle_jean
* Fix for restarting the stack when the gov.nist.javax.sip.TCP_POST_PARSING_THREAD_POOL_SIZE option is used
*
* Issue number:
* Obtained from:
* Submitted by: Jean Deruelle
* Reviewed by:
*
* Revision 1.34 2010/10/07 15:40:25 deruelle_jean
* Adding some cleaning up to POST_PARSING_THREAD_POOL option
*
* Issue number:
* Obtained from:
* Submitted by: Jean Deruelle
* Reviewed by:
*
* Revision 1.33 2010/10/07 15:03:49 deruelle_jean
* Fixing a deadlock on one post_parser_thread_pool option when there is only 1 thread and message ordering on multiple threads + adding non regression test case
*
* Issue number:
* Obtained from:
* Submitted by: Jean Deruelle
* Reviewed by:
*
* Revision 1.32 2010/08/19 19:18:01 deruelle_jean
* Fixing Message Order, there could be race conditions on TCP with multiple threads the order should be maintained
*
* Issue number: 301
* Obtained from:
* Submitted by: Jean Deruelle
* Reviewed by:
*
* Revision 1.31 2010/07/01 18:53:25 vralev
* Issue number: 301
* Obtained from: vralev
* Submitted by: vralev
* Reviewed by: ranga
*
* Handle better conflicting multiple settings. Taking into account only the first one without creating unused threadpools for other settings. In trunk.
*
* Revision 1.30 2010/07/01 18:22:56 vralev
* Issue number: 301
* Obtained from: vralev
* Submitted by: vralev
* Reviewed by: ranga
*
* Revision 1.29 2010/05/06 14:07:45 deruelle_jean
* Big update to improve performance by 50% in some cases, TCK + testsuite (cc-buildloop) green, Mobicents Sip Servlets TCK + testsuite green as well
*
* Issue number:
* Obtained from:
* Submitted by: Jean Deruelle
* Reviewed by:
*
* Revision 1.28 2010/03/19 17:29:46 deruelle_jean
* Adding getters and setters for the new factories
*
* Issue number:
* Obtained from:
* Submitted by: Jean Deruelle
* Reviewed by:
*
* Revision 1.27 2010/03/15 17:08:57 deruelle_jean
* Adding javadoc
*
* Issue number: 251
* Obtained from:
* Submitted by: Jean Deruelle
* Reviewed by: Ranga
*
* Revision 1.26 2010/03/15 17:01:21 deruelle_jean
* Applying patch allowing pluggable message parser implementation
*
* Issue number: 251
* Obtained from:
* Submitted by: Jean Deruelle
* Reviewed by: Ranga
*
* Revision 1.25 2010/02/27 17:34:04 mranga
* Issue number: 269
* Fix PipelinedMessageParser.java to use UTF-8 encoding when reading stream.
*
* Revision 1.24 2010/02/27 06:09:00 mranga
* Patch from Frederic
*
* Revision 1.23 2009/08/16 17:28:28 mranga
* Issue number: 208
* Obtained from:
* Submitted by:
* Reviewed by:
*
* Add authentication mechanism that uses H(username:domain:password)
*
* Revision 1.22 2009/07/17 18:58:02 emcho
* Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.
*
* Revision 1.21 2008/05/24 04:10:01 mranga
*
* Issue number: 158
* Obtained from:
* Submitted by:
* Reviewed by: mranga
*
* Deliver tx timeout for Canceled INVITE. Fix pipeline thread exit.
*
* Revision 1.20 2008/05/22 19:38:07 jbemmel
* Fix for issue 149: the logic wasn't always closing the internal socket pipe,
* causing the pipe reader thread to block indefinitely
*
* Repeatedly starting/stopping the stack then gives hanging threads
* Revision 1.19 2007/01/28 13:06:21 mranga
* Issue number: 99 Obtained from: Submitted by: Reviewed by: mranga
*
* Fixed PRACK handling null pointer exception (for proxy case) and cleanup of
* unused variables.
*
* CVS: ----------------------------------------------------------------------
* CVS: Issue number: CVS: If this change addresses one or more issues, CVS:
* then enter the issue number(s) here. CVS: Obtained from: CVS: If this change
* has been taken from another system, CVS: then name the system in this line,
* otherwise delete it. CVS: Submitted by: CVS: If this code has been
* contributed to the project by someone else; i.e., CVS: they sent us a patch
* or a set of diffs, then include their name/email CVS: address here. If this
* is your work then delete this line. CVS: Reviewed by: CVS: If we are doing
* pre-commit code reviews and someone else has CVS: reviewed your changes,
* include their name(s) here. CVS: If you have not had it reviewed then delete
* this line.
*
* Revision 1.18 2006/07/13 09:02:10 mranga Issue number: Obtained from:
* Submitted by: jeroen van bemmel Reviewed by: mranga Moved some changes from
* jain-sip-1.2 to java.net
*
* CVS: ----------------------------------------------------------------------
* CVS: Issue number: CVS: If this change addresses one or more issues, CVS:
* then enter the issue number(s) here. CVS: Obtained from: CVS: If this change
* has been taken from another system, CVS: then name the system in this line,
* otherwise delete it. CVS: Submitted by: CVS: If this code has been
* contributed to the project by someone else; i.e., CVS: they sent us a patch
* or a set of diffs, then include their name/email CVS: address here. If this
* is your work then delete this line. CVS: Reviewed by: CVS: If we are doing
* pre-commit code reviews and someone else has CVS: reviewed your changes,
* include their name(s) here. CVS: If you have not had it reviewed then delete
* this line.
*
* Revision 1.4 2006/06/19 06:47:27 mranga javadoc fixups
*
* Revision 1.3 2006/06/17 10:18:14 mranga Added some synchronization to the
* sequence number checking. Small javadoc fixups
*
* Revision 1.2 2006/06/16 15:26:28 mranga Added NIST disclaimer to all public
* domain files. Clean up some javadoc. Fixed a leak
*
* Revision 1.1.1.1 2005/10/04 17:12:35 mranga
*
* Import
*
*
* Revision 1.16 2004/11/30 23:28:14 mranga Issue number: 44 Submitted by: Rob
* Daugherty Reviewed by: M. Ranganathan
*
* TCP Pipelining truncates content when other end of pipe is closed.
*
* Revision 1.15 2004/05/30 18:55:56 mranga Reviewed by: mranga Move to timers
* and eliminate the Transaction scanner Thread to improve scalability and
* reduce cpu usage.
*
* Revision 1.14 2004/05/16 14:13:22 mranga Reviewed by: mranga Fixed the
* use-count issue reported by Peter Parnes. Added property to prevent against
* content-length dos attacks.
*
* Revision 1.13 2004/03/19 04:22:22 mranga Reviewed by: mranga Added IO Pacing
* for long writes - split write into chunks and flush after each chunk to avoid
* socket back pressure.
*
* Revision 1.12 2004/03/18 22:01:19 mranga Reviewed by: mranga Get rid of the
* PipedInputStream from pipelined parser to avoid a copy.
*
* Revision 1.11 2004/03/07 22:25:23 mranga Reviewed by: mranga Added a new
* configuration parameter that instructs the stack to drop a server connection
* after server transaction termination set
* gov.nist.javax.sip.CACHE_SERVER_CONNECTIONS=false for this Default behavior
* is true.
*
* Revision 1.10 2004/02/29 15:32:58 mranga Reviewed by: mranga bug fixes on
* limiting the max message size.
*
* Revision 1.9 2004/02/29 00:46:34 mranga Reviewed by: mranga Added new
* configuration property to limit max message size for TCP transport. The
* property is gov.nist.javax.sip.MAX_MESSAGE_SIZE
*
* Revision 1.8 2004/02/25 21:43:03 mranga Reviewed by: mranga Added a couple of
* todo's and removed some debug printlns that could slow code down by a bit.
*
* Revision 1.7 2004/02/25 20:52:46 mranga Reviewed by: mranga Fix TCP transport
* so messages in excess of 8192 bytes are accepted.
*
* Revision 1.6 2004/01/22 18:39:41 mranga Reviewed by: M. Ranganathan Moved the
* ifdef SIMULATION and associated tags to the first column so Prep preprocessor
* can deal with them.
*
* Revision 1.5 2004/01/22 14:23:45 mranga Reviewed by: mranga Fixed some minor
* formatting issues.
*
* Revision 1.4 2004/01/22 13:26:31 sverker Issue number: Obtained from:
* Submitted by: sverker Reviewed by: mranga
*
* Major reformat of code to conform with style guide. Resolved compiler and
* javadoc warnings. Added CVS tags.
*
* CVS: ----------------------------------------------------------------------
* CVS: Issue number: CVS: If this change addresses one or more issues, CVS:
* then enter the issue number(s) here. CVS: Obtained from: CVS: If this change
* has been taken from another system, CVS: then name the system in this line,
* otherwise delete it. CVS: Submitted by: CVS: If this code has been
* contributed to the project by someone else; i.e., CVS: they sent us a patch
* or a set of diffs, then include their name/email CVS: address here. If this
* is your work then delete this line. CVS: Reviewed by: CVS: If we are doing
* pre-commit code reviews and someone else has CVS: reviewed your changes,
* include their name(s) here. CVS: If you have not had it reviewed then delete
* this line.
*
*/
© 2015 - 2024 Weber Informatics LLC | Privacy Policy