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