1600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/*
2600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Conditions Of Use
3600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
4600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * This software was developed by employees of the National Institute of
5600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Standards and Technology (NIST), an agency of the Federal Government.
6600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Pursuant to title 15 Untied States Code Section 105, works of NIST
7600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * employees are not subject to copyright protection in the United States
8600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * and are considered to be in the public domain.  As a result, a formal
9600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * license is not needed to use the software.
10600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
11600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * This software is provided by NIST as a service and is expressly
12600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * provided "AS IS."  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
13600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
14600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
15600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * AND DATA ACCURACY.  NIST does not warrant or make any representations
16600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * regarding the use of the software or the results thereof, including but
17600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * not limited to the correctness, accuracy, reliability or usefulness of
18600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * the software.
19600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
20600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Permission to use this software is contingent upon your acceptance
21600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * of the terms of this agreement
22600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
23600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * .
24600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
25600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */
26600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/******************************************************************************
27600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).      *
28600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang ******************************************************************************/
29600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangpackage gov.nist.javax.sip.stack;
30600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
31600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.*;
32600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.message.*;
33600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.parser.*;
34600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.core.*;
35600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.net.*;
36600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.io.*;
37600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.text.ParseException;
38600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.util.TimerTask;
39600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
40600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.address.Hop;
41600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
42600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/*
43600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Ahmet Uyar <auyar@csit.fsu.edu>sent in a bug report for TCP operation of the JAIN sipStack.
44600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Niklas Uhrberg suggested that a mechanism be added to limit the number of simultaneous open
45600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * connections. The TLS Adaptations were contributed by Daniel Martinez. Hagai Sela contributed a
46600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * bug fix for symmetric nat. Jeroen van Bemmel added compensation for buggy clients ( Microsoft
47600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * RTC clients ). Bug fixes by viswashanti.kadiyala@antepo.com, Joost Yervante Damand
48600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */
49600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
50600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/**
51600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * This is a stack abstraction for TCP connections. This abstracts a stream of parsed messages.
52600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * The SIP sipStack starts this from the main SIPStack class for each connection that it accepts.
53600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * It starts a message parser in its own thread and talks to the message parser via a pipe. The
54600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * message parser calls back via the parseError or processMessage functions that are defined as
55600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * part of the SIPMessageListener interface.
56600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
57600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @see gov.nist.javax.sip.parser.PipelinedMsgParser
58600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
59600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
60600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @author M. Ranganathan <br/>
61600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
62600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @version 1.2 $Revision: 1.59 $ $Date: 2009/11/20 04:45:53 $
63600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */
64600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangpublic class TCPMessageChannel extends MessageChannel implements SIPMessageListener, Runnable,
65600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        RawMessageChannel {
66600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
67600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private Socket mySock;
68600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
69600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private PipelinedMsgParser myParser;
70600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
71600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected InputStream myClientInputStream; // just to pass to thread.
72600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
73600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected OutputStream myClientOutputStream;
74600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
75600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected String key;
76600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
77600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected boolean isCached;
78600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
79600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected boolean isRunning;
80600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
81600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private Thread mythread;
82600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
83600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected SIPTransactionStack sipStack;
84600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
85600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected String myAddress;
86600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
87600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected int myPort;
88600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
89600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected InetAddress peerAddress;
90600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
91600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected int peerPort;
92600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
93600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected String peerProtocol;
94600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
95600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // Incremented whenever a transaction gets assigned
96600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // to the message channel and decremented when
97600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // a transaction gets freed from the message channel.
98600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // protected int useCount;
99600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
100600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private TCPMessageProcessor tcpMessageProcessor;
101600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
102600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected TCPMessageChannel(SIPTransactionStack sipStack) {
103600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.sipStack = sipStack;
104600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
105600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
106600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
107600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
108600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Constructor - gets called from the SIPStack class with a socket on accepting a new client.
109600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * All the processing of the message is done here with the sipStack being freed up to handle
110600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * new connections. The sock input is the socket that is returned from the accept. Global data
111600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * that is shared by all threads is accessible in the Server structure.
112600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
113600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param sock Socket from which to read and write messages. The socket is already connected
114600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *        (was created as a result of an accept).
115600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
116600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param sipStack Ptr to SIP Stack
117600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
118600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
119600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected TCPMessageChannel(Socket sock, SIPTransactionStack sipStack,
120600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            TCPMessageProcessor msgProcessor) throws IOException {
121600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
122600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (sipStack.isLoggingEnabled()) {
123600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            sipStack.getStackLogger().logDebug("creating new TCPMessageChannel ");
124600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            sipStack.getStackLogger().logStackTrace();
125600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
126600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        mySock = sock;
127600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        peerAddress = mySock.getInetAddress();
128600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        myAddress = msgProcessor.getIpAddress().getHostAddress();
129600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        myClientInputStream = mySock.getInputStream();
130600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        myClientOutputStream = mySock.getOutputStream();
131600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        mythread = new Thread(this);
132600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        mythread.setDaemon(true);
133600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        mythread.setName("TCPMessageChannelThread");
134600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Stash away a pointer to our sipStack structure.
135600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.sipStack = sipStack;
136600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.peerPort = mySock.getPort();
137600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
138600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.tcpMessageProcessor = msgProcessor;
139600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.myPort = this.tcpMessageProcessor.getPort();
140600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Bug report by Vishwashanti Raj Kadiayl
141600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        super.messageProcessor = msgProcessor;
142600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Can drop this after response is sent potentially.
143600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        mythread.start();
144600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
145600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
146600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
147600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Constructor - connects to the given inet address. Acknowledgement -- Lamine Brahimi (IBM
148600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Zurich) sent in a bug fix for this method. A thread was being uncessarily created.
149600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
150600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param inetAddr inet address to connect to.
151600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param sipStack is the sip sipStack from which we are created.
152600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @throws IOException if we cannot connect.
153600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
154600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected TCPMessageChannel(InetAddress inetAddr, int port, SIPTransactionStack sipStack,
155600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            TCPMessageProcessor messageProcessor) throws IOException {
156600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (sipStack.isLoggingEnabled()) {
157600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            sipStack.getStackLogger().logDebug("creating new TCPMessageChannel ");
158600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            sipStack.getStackLogger().logStackTrace();
159600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
160600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.peerAddress = inetAddr;
161600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.peerPort = port;
162600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.myPort = messageProcessor.getPort();
163600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.peerProtocol = "TCP";
164600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.sipStack = sipStack;
165600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.tcpMessageProcessor = messageProcessor;
166600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.myAddress = messageProcessor.getIpAddress().getHostAddress();
167600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Bug report by Vishwashanti Raj Kadiayl
168600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.key = MessageChannel.getKey(peerAddress, peerPort, "TCP");
169600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        super.messageProcessor = messageProcessor;
170600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
171600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
172600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
173600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
174600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Returns "true" as this is a reliable transport.
175600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
176600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public boolean isReliable() {
177600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return true;
178600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
179600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
180600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
181600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Close the message channel.
182600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
183600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void close() {
184600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        try {
185600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (mySock != null) {
186600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                mySock.close();
187600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                mySock = null;
188600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
189600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (sipStack.isLoggingEnabled())
190600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                sipStack.getStackLogger().logDebug("Closing message Channel " + this);
191600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } catch (IOException ex) {
192600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (sipStack.isLoggingEnabled())
193600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                sipStack.getStackLogger().logDebug("Error closing socket " + ex);
194600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
195600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
196600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
197600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
198600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get my SIP Stack.
199600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
200600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return The SIP Stack for this message channel.
201600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
202600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public SIPTransactionStack getSIPStack() {
203600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return sipStack;
204600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
205600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
206600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
207600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * get the transport string.
208600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
209600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return "tcp" in this case.
210600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
211600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public String getTransport() {
212600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return "TCP";
213600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
214600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
215600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
216600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * get the address of the client that sent the data to us.
217600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
218600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return Address of the client that sent us data that resulted in this channel being
219600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *         created.
220600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
221600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public String getPeerAddress() {
222600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (peerAddress != null) {
223600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return peerAddress.getHostAddress();
224600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else
225600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return getHost();
226600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
227600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
228600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected InetAddress getPeerInetAddress() {
229600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return peerAddress;
230600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
231600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
232600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public String getPeerProtocol() {
233600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return this.peerProtocol;
234600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
235600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
236600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
237600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Send message to whoever is connected to us. Uses the topmost via address to send to.
238600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
239600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param msg is the message to send.
240600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param retry
241600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
242600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private void sendMessage(byte[] msg, boolean retry) throws IOException {
243600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
244600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        /*
245600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * Patch from kircuv@dev.java.net (Issue 119 ) This patch avoids the case where two
246600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * TCPMessageChannels are now pointing to the same socket.getInputStream().
247600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         *
248600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * JvB 22/5 removed
249600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         */
250600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang       // Socket s = this.sipStack.ioHandler.getSocket(IOHandler.makeKey(
251600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang       // this.peerAddress, this.peerPort));
252600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        Socket sock = this.sipStack.ioHandler.sendBytes(this.messageProcessor.getIpAddress(),
253600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                this.peerAddress, this.peerPort, this.peerProtocol, msg, retry, this);
254600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
255600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Created a new socket so close the old one and stick the new
256600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // one in its place but dont do this if it is a datagram socket.
257600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // (could have replied via udp but received via tcp!).
258600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // if (mySock == null && s != null) {
259600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // this.uncache();
260600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // } else
261600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (sock != mySock && sock != null) {
262600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            try {
263600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (mySock != null)
264600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    mySock.close();
265600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } catch (IOException ex) {
266600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
267600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            mySock = sock;
268600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.myClientInputStream = mySock.getInputStream();
269600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.myClientOutputStream = mySock.getOutputStream();
270600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            Thread thread = new Thread(this);
271600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            thread.setDaemon(true);
272600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            thread.setName("TCPMessageChannelThread");
273600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            thread.start();
274600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
275600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
276600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
277600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
278600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
279600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Return a formatted message to the client. We try to re-connect with the peer on the other
280600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * end if possible.
281600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
282600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param sipMessage Message to send.
283600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @throws IOException If there is an error sending the message
284600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
285600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void sendMessage(SIPMessage sipMessage) throws IOException {
286600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        byte[] msg = sipMessage.encodeAsBytes(this.getTransport());
287600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
288600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        long time = System.currentTimeMillis();
289600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
290600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // JvB: also retry for responses, if the connection is gone we should
291600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // try to reconnect
292600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.sendMessage(msg, /* sipMessage instanceof SIPRequest */true);
293600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
294600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (this.sipStack.getStackLogger().isLoggingEnabled(ServerLogger.TRACE_MESSAGES))
295600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            logMessage(sipMessage, peerAddress, peerPort, time);
296600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
297600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
298600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
299600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Send a message to a specified address.
300600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
301600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param message Pre-formatted message to send.
302600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param receiverAddress Address to send it to.
303600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param receiverPort Receiver port.
304600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @throws IOException If there is a problem connecting or sending.
305600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
306600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void sendMessage(byte message[], InetAddress receiverAddress, int receiverPort,
307600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            boolean retry) throws IOException {
308600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (message == null || receiverAddress == null)
309600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw new IllegalArgumentException("Null argument");
310600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         Socket sock = this.sipStack.ioHandler.sendBytes(this.messageProcessor.getIpAddress(),
311600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                receiverAddress, receiverPort, "TCP", message, retry, this);
312600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (sock != mySock && sock != null) {
313600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (mySock != null) {
314600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                /*
315600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                 * Delay the close of the socket for some time in case it is being used.
316600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                 */
317600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                sipStack.getTimer().schedule(new TimerTask() {
318600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    @Override
319600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    public boolean cancel() {
320600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        try {
321600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            mySock.close();
322600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            super.cancel();
323600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        } catch (IOException ex) {
324600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
325600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        }
326600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        return true;
327600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
328600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
329600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    @Override
330600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    public void run() {
331600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        try {
332600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            mySock.close();
333600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        } catch (IOException ex) {
334600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
335600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        }
336600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
337600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }, 8000);
338600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
339600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
340600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            mySock = sock;
341600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.myClientInputStream = mySock.getInputStream();
342600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.myClientOutputStream = mySock.getOutputStream();
343600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // start a new reader on this end of the pipe.
344600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            Thread mythread = new Thread(this);
345600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            mythread.setDaemon(true);
346600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            mythread.setName("TCPMessageChannelThread");
347600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            mythread.start();
348600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
349600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
350600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
351600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
352600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
353600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Exception processor for exceptions detected from the parser. (This is invoked by the parser
354600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * when an error is detected).
355600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
356600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param sipMessage -- the message that incurred the error.
357600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param ex -- parse exception detected by the parser.
358600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param header -- header that caused the error.
359600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @throws ParseException Thrown if we want to reject the message.
360600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
361600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void handleException(ParseException ex, SIPMessage sipMessage, Class hdrClass,
362600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            String header, String message) throws ParseException {
363600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (sipStack.isLoggingEnabled())
364600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            sipStack.getStackLogger().logException(ex);
365600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Log the bad message for later reference.
366600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if ((hdrClass != null)
367600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                && (hdrClass.equals(From.class) || hdrClass.equals(To.class)
368600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        || hdrClass.equals(CSeq.class) || hdrClass.equals(Via.class)
369600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        || hdrClass.equals(CallID.class) || hdrClass.equals(RequestLine.class) || hdrClass
370600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        .equals(StatusLine.class))) {
371600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (sipStack.isLoggingEnabled()) {
372600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                sipStack.getStackLogger().logDebug(
373600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        "Encountered Bad Message \n" + sipMessage.toString());
374600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
375600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
376600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // JvB: send a 400 response for requests (except ACK)
377600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Currently only UDP, @todo also other transports
378600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            String msgString = sipMessage.toString();
379600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (!msgString.startsWith("SIP/") && !msgString.startsWith("ACK ")) {
380600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
381600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                String badReqRes = createBadReqRes(msgString, ex);
382600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (badReqRes != null) {
383600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (sipStack.isLoggingEnabled()) {
384600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        sipStack.getStackLogger().logDebug("Sending automatic 400 Bad Request:");
385600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        sipStack.getStackLogger().logDebug(badReqRes);
386600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
387600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    try {
388600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        this.sendMessage(badReqRes.getBytes(), this.getPeerInetAddress(), this
389600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                .getPeerPort(), false);
390600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    } catch (IOException e) {
391600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        this.sipStack.getStackLogger().logException(e);
392600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
393600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } else {
394600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (sipStack.isLoggingEnabled()) {
395600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        sipStack.getStackLogger().logDebug(
396600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                "Could not formulate automatic 400 Bad Request");
397600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
398600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
399600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
400600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
401600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw ex;
402600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else {
403600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            sipMessage.addUnparsed(header);
404600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
405600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
406600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
407600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
408600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Gets invoked by the parser as a callback on successful message parsing (i.e. no parser
409600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * errors).
410600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
411600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param sipMessage Mesage to process (this calls the application for processing the
412600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *        message).
413600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
414600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void processMessage(SIPMessage sipMessage) throws Exception {
415600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        try {
416600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (sipMessage.getFrom() == null
417600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    || // sipMessage.getFrom().getTag()
418600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // == null ||
419600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    sipMessage.getTo() == null || sipMessage.getCallId() == null
420600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    || sipMessage.getCSeq() == null || sipMessage.getViaHeaders() == null) {
421600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                String badmsg = sipMessage.encode();
422600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (sipStack.isLoggingEnabled()) {
423600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    sipStack.getStackLogger().logDebug(">>> Dropped Bad Msg");
424600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    sipStack.getStackLogger().logDebug(badmsg);
425600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
426600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
427600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                return;
428600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
429600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
430600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            ViaList viaList = sipMessage.getViaHeaders();
431600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // For a request
432600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // first via header tells where the message is coming from.
433600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // For response, this has already been recorded in the outgoing
434600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // message.
435600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (sipMessage instanceof SIPRequest) {
436600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                Via v = (Via) viaList.getFirst();
437600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                Hop hop = sipStack.addressResolver.resolveAddress(v.getHop());
438600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                this.peerProtocol = v.getTransport();
439600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                try {
440600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    this.peerAddress = mySock.getInetAddress();
441600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // Check to see if the received parameter matches
442600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // the peer address and tag it appropriately.
443600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
444600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // JvB: dont do this. It is both costly and incorrect
445600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // Must set received also when it is a FQDN, regardless
446600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // whether
447600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // it resolves to the correct IP address
448600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // InetAddress sentByAddress =
449600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // InetAddress.getByName(hop.getHost());
450600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // JvB: if sender added 'rport', must always set received
451600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (v.hasParameter(Via.RPORT)
452600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            || !hop.getHost().equals(this.peerAddress.getHostAddress())) {
453600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        v.setParameter(Via.RECEIVED, this.peerAddress.getHostAddress());
454600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
455600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // @@@ hagai
456600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // JvB: technically, may only do this when Via already
457600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // contains
458600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // rport
459600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    v.setParameter(Via.RPORT, Integer.toString(this.peerPort));
460600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } catch (java.text.ParseException ex) {
461600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    InternalErrorHandler.handleException(ex, sipStack.getStackLogger());
462600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
463600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Use this for outgoing messages as well.
464600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (!this.isCached) {
465600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    ((TCPMessageProcessor) this.messageProcessor).cacheMessageChannel(this);
466600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    this.isCached = true;
467600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    int remotePort = ((java.net.InetSocketAddress) mySock.getRemoteSocketAddress()).getPort();
468600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    String key = IOHandler.makeKey(mySock.getInetAddress(), remotePort);
469600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    sipStack.ioHandler.putSocket(key, mySock);
470600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
471600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
472600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
473600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
474600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Foreach part of the request header, fetch it and process it
475600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
476600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            long receptionTime = System.currentTimeMillis();
477600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
478600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (sipMessage instanceof SIPRequest) {
479600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // This is a request - process the request.
480600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                SIPRequest sipRequest = (SIPRequest) sipMessage;
481600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Create a new sever side request processor for this
482600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // message and let it handle the rest.
483600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
484600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (sipStack.isLoggingEnabled()) {
485600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    sipStack.getStackLogger().logDebug("----Processing Message---");
486600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
487600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
488600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Check for reasonable size - reject message
489600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // if it is too long.
490600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (this.sipStack.getStackLogger().isLoggingEnabled(ServerLogger.TRACE_MESSAGES)) {
491600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    sipStack.serverLogger.logMessage(sipMessage, this.getPeerHostPort().toString(),
492600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            this.getMessageProcessor().getIpAddress().getHostAddress() + ":"
493600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                    + this.getMessageProcessor().getPort(), false, receptionTime);
494600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
495600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
496600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
497600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (sipStack.getMaxMessageSize() > 0
498600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        && sipRequest.getSize()
499600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                + (sipRequest.getContentLength() == null ? 0 : sipRequest
500600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                        .getContentLength().getContentLength()) > sipStack
501600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                .getMaxMessageSize()) {
502600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    SIPResponse sipResponse = sipRequest
503600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            .createResponse(SIPResponse.MESSAGE_TOO_LARGE);
504600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    byte[] resp = sipResponse.encodeAsBytes(this.getTransport());
505600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    this.sendMessage(resp, false);
506600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    throw new Exception("Message size exceeded");
507600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
508600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
509600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                ServerRequestInterface sipServerRequest = sipStack.newSIPServerRequest(
510600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        sipRequest, this);
511600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
512600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (sipServerRequest != null) {
513600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    try {
514600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        sipServerRequest.processRequest(sipRequest, this);
515600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    } finally {
516600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        if (sipServerRequest instanceof SIPTransaction) {
517600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            SIPServerTransaction sipServerTx = (SIPServerTransaction) sipServerRequest;
518600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            if (!sipServerTx.passToListener())
519600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                ((SIPTransaction) sipServerRequest).releaseSem();
520600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        }
521600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
522600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } else {
523600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                	if (sipStack.isLoggingEnabled())
524600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                		this.sipStack.getStackLogger()
525600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            .logWarning("Dropping request -- could not acquire semaphore in 10 sec");
526600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
527600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
528600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } else {
529600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                SIPResponse sipResponse = (SIPResponse) sipMessage;
530600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // JvB: dont do this
531600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // if (sipResponse.getStatusCode() == 100)
532600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // sipResponse.getTo().removeParameter("tag");
533600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                try {
534600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    sipResponse.checkHeaders();
535600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } catch (ParseException ex) {
536600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (sipStack.isLoggingEnabled())
537600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        sipStack.getStackLogger()
538600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                .logError("Dropping Badly formatted response message >>> "
539600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                        + sipResponse);
540600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    return;
541600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
542600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // This is a response message - process it.
543600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Check the size of the response.
544600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // If it is too large dump it silently.
545600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (sipStack.getMaxMessageSize() > 0
546600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        && sipResponse.getSize()
547600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                + (sipResponse.getContentLength() == null ? 0 : sipResponse
548600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                        .getContentLength().getContentLength()) > sipStack
549600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                .getMaxMessageSize()) {
550600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (sipStack.isLoggingEnabled())
551600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        this.sipStack.getStackLogger().logDebug("Message size exceeded");
552600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    return;
553600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
554600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
555600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                ServerResponseInterface sipServerResponse = sipStack.newSIPServerResponse(
556600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        sipResponse, this);
557600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (sipServerResponse != null) {
558600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    try {
559600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        if (sipServerResponse instanceof SIPClientTransaction
560600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                && !((SIPClientTransaction) sipServerResponse)
561600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                        .checkFromTag(sipResponse)) {
562600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            if (sipStack.isLoggingEnabled())
563600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                sipStack.getStackLogger()
564600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                        .logError("Dropping response message with invalid tag >>> "
565600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                                + sipResponse);
566600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            return;
567600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        }
568600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
569600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        sipServerResponse.processResponse(sipResponse, this);
570600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    } finally {
571600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        if (sipServerResponse instanceof SIPTransaction
572600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                && !((SIPTransaction) sipServerResponse).passToListener())
573600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            ((SIPTransaction) sipServerResponse).releaseSem();
574600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
575600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } else {
576600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    sipStack
577600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            .getStackLogger()
578600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            .logWarning(
579600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                    "Application is blocked -- could not acquire semaphore -- dropping response");
580600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
581600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
582600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } finally {
583600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
584600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
585600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
586600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
587600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * This gets invoked when thread.start is called from the constructor. Implements a message
588600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * loop - reading the tcp connection and processing messages until we are done or the other
589600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * end has closed.
590600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
591600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void run() {
592600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        Pipeline hispipe = null;
593600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Create a pipeline to connect to our message parser.
594600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        hispipe = new Pipeline(myClientInputStream, sipStack.readTimeout,
595600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                ((SIPTransactionStack) sipStack).getTimer());
596600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Create a pipelined message parser to read and parse
597600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // messages that we write out to him.
598600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        myParser = new PipelinedMsgParser(this, hispipe, this.sipStack.getMaxMessageSize());
599600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Start running the parser thread.
600600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        myParser.processInput();
601600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // bug fix by Emmanuel Proulx
602600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        int bufferSize = 4096;
603600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.tcpMessageProcessor.useCount++;
604600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.isRunning = true;
605600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        try {
606600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            while (true) {
607600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                try {
608600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    byte[] msg = new byte[bufferSize];
609600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    int nbytes = myClientInputStream.read(msg, 0, bufferSize);
610600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // no more bytes to read...
611600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (nbytes == -1) {
612600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        hispipe.write("\r\n\r\n".getBytes("UTF-8"));
613600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        try {
614600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            if (sipStack.maxConnections != -1) {
615600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                synchronized (tcpMessageProcessor) {
616600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                    tcpMessageProcessor.nConnections--;
617600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                    tcpMessageProcessor.notify();
618600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                }
619600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            }
620600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            hispipe.close();
621600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            mySock.close();
622600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        } catch (IOException ioex) {
623600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        }
624600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        return;
625600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
626600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    hispipe.write(msg, 0, nbytes);
627600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
628600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } catch (IOException ex) {
629600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // Terminate the message.
630600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    try {
631600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        hispipe.write("\r\n\r\n".getBytes("UTF-8"));
632600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    } catch (Exception e) {
633600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        // InternalErrorHandler.handleException(e);
634600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
635600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
636600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    try {
637600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        if (sipStack.isLoggingEnabled())
638600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            sipStack.getStackLogger().logDebug("IOException  closing sock " + ex);
639600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        try {
640600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            if (sipStack.maxConnections != -1) {
641600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                synchronized (tcpMessageProcessor) {
642600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                    tcpMessageProcessor.nConnections--;
643600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                    // System.out.println("Notifying!");
644600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                    tcpMessageProcessor.notify();
645600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                }
646600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            }
647600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            mySock.close();
648600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            hispipe.close();
649600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        } catch (IOException ioex) {
650600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        }
651600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    } catch (Exception ex1) {
652600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        // Do nothing.
653600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
654600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    return;
655600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } catch (Exception ex) {
656600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    InternalErrorHandler.handleException(ex, sipStack.getStackLogger());
657600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
658600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
659600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } finally {
660600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.isRunning = false;
661600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.tcpMessageProcessor.remove(this);
662600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.tcpMessageProcessor.useCount--;
663600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            myParser.close();
664600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
665600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
666600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
667600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
668600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected void uncache() {
669600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    	if (isCached && !isRunning) {
670600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    		this.tcpMessageProcessor.remove(this);
671600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    	}
672600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
673600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
674600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
675600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Equals predicate.
676600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
677600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param other is the other object to compare ourselves to for equals
678600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
679600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
680600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public boolean equals(Object other) {
681600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
682600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (!this.getClass().equals(other.getClass()))
683600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return false;
684600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        else {
685600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            TCPMessageChannel that = (TCPMessageChannel) other;
686600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (this.mySock != that.mySock)
687600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                return false;
688600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            else
689600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                return true;
690600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
691600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
692600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
693600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
694600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get an identifying key. This key is used to cache the connection and re-use it if
695600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * necessary.
696600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
697600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public String getKey() {
698600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (this.key != null) {
699600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return this.key;
700600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else {
701600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.key = MessageChannel.getKey(this.peerAddress, this.peerPort, "TCP");
702600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return this.key;
703600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
704600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
705600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
706600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
707600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get the host to assign to outgoing messages.
708600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
709600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return the host to assign to the via header.
710600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
711600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public String getViaHost() {
712600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return myAddress;
713600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
714600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
715600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
716600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get the port for outgoing messages sent from the channel.
717600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
718600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return the port to assign to the via header.
719600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
720600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public int getViaPort() {
721600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return myPort;
722600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
723600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
724600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
725600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get the port of the peer to whom we are sending messages.
726600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
727600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return the peer port.
728600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
729600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public int getPeerPort() {
730600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return peerPort;
731600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
732600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
733600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public int getPeerPacketSourcePort() {
734600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return this.peerPort;
735600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
736600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
737600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public InetAddress getPeerPacketSourceAddress() {
738600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return this.peerAddress;
739600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
740600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
741600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
742600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * TCP Is not a secure protocol.
743600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
744600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public boolean isSecure() {
745600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return false;
746600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
747600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang}
748