Home | History | Annotate | Download | only in stack
      1 /*
      2  * Conditions Of Use
      3  *
      4  * This software was developed by employees of the National Institute of
      5  * Standards and Technology (NIST), an agency of the Federal Government.
      6  * Pursuant to title 15 Untied States Code Section 105, works of NIST
      7  * employees are not subject to copyright protection in the United States
      8  * and are considered to be in the public domain.  As a result, a formal
      9  * license is not needed to use the software.
     10  *
     11  * This software is provided by NIST as a service and is expressly
     12  * provided "AS IS."  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
     13  * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
     14  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
     15  * AND DATA ACCURACY.  NIST does not warrant or make any representations
     16  * regarding the use of the software or the results thereof, including but
     17  * not limited to the correctness, accuracy, reliability or usefulness of
     18  * the software.
     19  *
     20  * Permission to use this software is contingent upon your acceptance
     21  * of the terms of this agreement
     22  *
     23  * .
     24  *
     25  */
     26 /* This class is entirely derived from TCPMessageChannel,
     27  * by making some minor changes. Daniel J. Martinez Manzano <dani (at) dif.um.es>
     28  * made these changes. Ahmet Uyar
     29  * <auyar (at) csit.fsu.edu>sent in a bug report for TCP operation of the
     30  * JAIN sipStack. Niklas Uhrberg suggested that a mechanism be added to
     31  * limit the number of simultaneous open connections. The TLS
     32  * Adaptations were contributed by Daniel Martinez. Hagai Sela
     33  * contributed a bug fix for symmetric nat. Jeroen van Bemmel
     34  * added compensation for buggy clients ( Microsoft RTC clients ).
     35  * Bug fixes by viswashanti.kadiyala (at) antepo.com, Joost Yervante Damand
     36  * Lamine Brahimi (IBM Zurich) sent in a bug fix - a thread was being uncessarily created.
     37  */
     38 
     39 /******************************************************************************
     40  * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).      *
     41  ******************************************************************************/
     42 package gov.nist.javax.sip.stack;
     43 
     44 import gov.nist.javax.sip.header.*;
     45 import gov.nist.javax.sip.message.*;
     46 import gov.nist.javax.sip.parser.*;
     47 import gov.nist.core.*;
     48 import java.net.*;
     49 import java.io.*;
     50 import java.text.ParseException;
     51 
     52 import javax.net.ssl.HandshakeCompletedListener;
     53 import javax.net.ssl.SSLSocket;
     54 import javax.sip.address.Hop;
     55 import javax.sip.message.Response;
     56 
     57 /**
     58  * This is sipStack for TLS connections. This abstracts a stream of parsed messages. The SIP
     59  * sipStack starts this from the main SIPStack class for each connection that it accepts. It
     60  * starts a message parser in its own thread and talks to the message parser via a pipe. The
     61  * message parser calls back via the parseError or processMessage functions that are defined as
     62  * part of the SIPMessageListener interface.
     63  *
     64  * @see gov.nist.javax.sip.parser.PipelinedMsgParser
     65  *
     66  *
     67  * @author M. Ranganathan
     68  *
     69  *
     70  * @version 1.2 $Revision: 1.27 $ $Date: 2010/01/10 00:13:14 $
     71  */
     72 public final class TLSMessageChannel extends MessageChannel implements SIPMessageListener,
     73         Runnable, RawMessageChannel {
     74 
     75     private Socket mySock;
     76 
     77     private PipelinedMsgParser myParser;
     78 
     79     private InputStream myClientInputStream; // just to pass to thread.
     80 
     81     private String key;
     82 
     83     protected boolean isCached;
     84 
     85     protected boolean isRunning;
     86 
     87     private Thread mythread;
     88 
     89     private String myAddress;
     90 
     91     private int myPort;
     92 
     93     private InetAddress peerAddress;
     94 
     95     private int peerPort;
     96 
     97     private String peerProtocol;
     98 
     99     // Incremented whenever a transaction gets assigned
    100     // to the message channel and decremented when
    101     // a transaction gets freed from the message channel.
    102     // protected int useCount = 0;
    103 
    104     private TLSMessageProcessor tlsMessageProcessor;
    105 
    106     private SIPTransactionStack sipStack;
    107 
    108     private HandshakeCompletedListener handshakeCompletedListener;
    109 
    110     /**
    111      * Constructor - gets called from the SIPStack class with a socket on accepting a new client.
    112      * All the processing of the message is done here with the sipStack being freed up to handle
    113      * new connections. The sock input is the socket that is returned from the accept. Global data
    114      * that is shared by all threads is accessible in the Server structure.
    115      *
    116      * @param sock Socket from which to read and write messages. The socket is already connected
    117      *        (was created as a result of an accept).
    118      *
    119      * @param sipStack Ptr to SIP Stack
    120      *
    121      * @param msgProcessor -- the message processor that created us.
    122      */
    123 
    124     protected TLSMessageChannel(Socket sock, SIPTransactionStack sipStack,
    125             TLSMessageProcessor msgProcessor) throws IOException {
    126         if (sipStack.isLoggingEnabled()) {
    127             sipStack.getStackLogger().logDebug("creating new TLSMessageChannel (incoming)");
    128             sipStack.getStackLogger().logStackTrace();
    129         }
    130 
    131         mySock = (SSLSocket) sock;
    132         if ( sock instanceof SSLSocket ) {
    133 
    134             SSLSocket sslSock = (SSLSocket) sock;
    135             sslSock.setNeedClientAuth(true);
    136             this.handshakeCompletedListener = new HandshakeCompletedListenerImpl(this);
    137             sslSock.addHandshakeCompletedListener(this.handshakeCompletedListener);
    138             sslSock.startHandshake();
    139 
    140         }
    141 
    142         peerAddress = mySock.getInetAddress();
    143         myAddress = msgProcessor.getIpAddress().getHostAddress();
    144         myClientInputStream = mySock.getInputStream();
    145 
    146         mythread = new Thread(this);
    147         mythread.setDaemon(true);
    148         mythread.setName("TLSMessageChannelThread");
    149         // Stash away a pointer to our sipStack structure.
    150         this.sipStack = sipStack;
    151 
    152         this.tlsMessageProcessor = msgProcessor;
    153         this.myPort = this.tlsMessageProcessor.getPort();
    154         this.peerPort = mySock.getPort();
    155         // Bug report by Vishwashanti Raj Kadiayl
    156         super.messageProcessor = msgProcessor;
    157         // Can drop this after response is sent potentially.
    158         mythread.start();
    159     }
    160 
    161     /**
    162      * Constructor - connects to the given inet address.
    163      *
    164      * @param inetAddr inet address to connect to.
    165      * @param sipStack is the sip sipStack from which we are created.
    166      * @param messageProcessor -- the message processor that created us.
    167      * @throws IOException if we cannot connect.
    168      */
    169     protected TLSMessageChannel(InetAddress inetAddr, int port, SIPTransactionStack sipStack,
    170             TLSMessageProcessor messageProcessor) throws IOException {
    171         if (sipStack.isLoggingEnabled()) {
    172             sipStack.getStackLogger().logDebug("creating new TLSMessageChannel (outgoing)");
    173             sipStack.getStackLogger().logStackTrace();
    174         }
    175         this.peerAddress = inetAddr;
    176         this.peerPort = port;
    177         this.myPort = messageProcessor.getPort();
    178         this.peerProtocol = "TLS";
    179         this.sipStack = sipStack;
    180         this.tlsMessageProcessor = messageProcessor;
    181         this.myAddress = messageProcessor.getIpAddress().getHostAddress();
    182         this.key = MessageChannel.getKey(peerAddress, peerPort, "TLS");
    183         super.messageProcessor = messageProcessor;
    184 
    185     }
    186 
    187     /**
    188      * Returns "true" as this is a reliable transport.
    189      */
    190     public boolean isReliable() {
    191         return true;
    192     }
    193 
    194     /**
    195      * Close the message channel.
    196      */
    197     public void close() {
    198         try {
    199             if (mySock != null)
    200                 mySock.close();
    201             if (sipStack.isLoggingEnabled())
    202                 sipStack.getStackLogger().logDebug("Closing message Channel " + this);
    203         } catch (IOException ex) {
    204             if (sipStack.isLoggingEnabled())
    205                 sipStack.getStackLogger().logDebug("Error closing socket " + ex);
    206         }
    207     }
    208 
    209     /**
    210      * Get my SIP Stack.
    211      *
    212      * @return The SIP Stack for this message channel.
    213      */
    214     public SIPTransactionStack getSIPStack() {
    215         return sipStack;
    216     }
    217 
    218     /**
    219      * get the transport string.
    220      *
    221      * @return "tcp" in this case.
    222      */
    223     public String getTransport() {
    224         return "tls";
    225     }
    226 
    227     /**
    228      * get the address of the client that sent the data to us.
    229      *
    230      * @return Address of the client that sent us data that resulted in this channel being
    231      *         created.
    232      */
    233     public String getPeerAddress() {
    234         if (peerAddress != null) {
    235             return peerAddress.getHostAddress();
    236         } else
    237             return getHost();
    238     }
    239 
    240     protected InetAddress getPeerInetAddress() {
    241         return peerAddress;
    242     }
    243 
    244     public String getPeerProtocol() {
    245         return this.peerProtocol;
    246     }
    247 
    248     /**
    249      * Send message to whoever is connected to us. Uses the topmost via address to send to.
    250      *
    251      * @param msg is the message to send.
    252      * @param retry
    253      */
    254     private void sendMessage(byte[] msg, boolean retry) throws IOException {
    255         Socket sock = this.sipStack.ioHandler.sendBytes(
    256                 this.getMessageProcessor().getIpAddress(), this.peerAddress, this.peerPort,
    257                 this.peerProtocol, msg, retry,this);
    258         // Created a new socket so close the old one and stick the new
    259         // one in its place but dont do this if it is a datagram socket.
    260         // (could have replied via udp but received via tcp!).
    261         if (sock != mySock && sock != null) {
    262             try {
    263                 if (mySock != null)
    264                     mySock.close();
    265             } catch (IOException ex) {
    266             }
    267             mySock = sock;
    268             this.myClientInputStream = mySock.getInputStream();
    269 
    270             Thread thread = new Thread(this);
    271             thread.setDaemon(true);
    272             thread.setName("TLSMessageChannelThread");
    273             thread.start();
    274         }
    275 
    276     }
    277 
    278     /**
    279      * Return a formatted message to the client. We try to re-connect with the peer on the other
    280      * end if possible.
    281      *
    282      * @param sipMessage Message to send.
    283      * @throws IOException If there is an error sending the message
    284      */
    285     public void sendMessage(SIPMessage sipMessage) throws IOException {
    286         byte[] msg = sipMessage.encodeAsBytes(this.getTransport());
    287 
    288         long time = System.currentTimeMillis();
    289 
    290         this.sendMessage(msg, sipMessage instanceof SIPRequest);
    291 
    292         if (this.sipStack.getStackLogger().isLoggingEnabled(ServerLogger.TRACE_MESSAGES))
    293             logMessage(sipMessage, peerAddress, peerPort, time);
    294     }
    295 
    296     /**
    297      * Send a message to a specified address.
    298      *
    299      * @param message Pre-formatted message to send.
    300      * @param receiverAddress Address to send it to.
    301      * @param receiverPort Receiver port.
    302      * @throws IOException If there is a problem connecting or sending.
    303      */
    304     public void sendMessage(byte message[], InetAddress receiverAddress, int receiverPort,
    305             boolean retry) throws IOException {
    306         if (message == null || receiverAddress == null)
    307             throw new IllegalArgumentException("Null argument");
    308         Socket sock = this.sipStack.ioHandler.sendBytes(this.messageProcessor.getIpAddress(),
    309                 receiverAddress, receiverPort, "TLS", message, retry, this);
    310         //
    311         // Created a new socket so close the old one and s
    312         // Check for null (bug fix sent in by Christophe)
    313         if (sock != mySock && sock != null) {
    314             try {
    315                 if (mySock != null)
    316                     mySock.close();
    317             } catch (IOException ex) {
    318                 /* ignore */
    319             }
    320             mySock = sock;
    321             this.myClientInputStream = mySock.getInputStream();
    322 
    323             // start a new reader on this end of the pipe.
    324             Thread mythread = new Thread(this);
    325             mythread.setDaemon(true);
    326             mythread.setName("TLSMessageChannelThread");
    327             mythread.start();
    328         }
    329 
    330     }
    331 
    332     /**
    333      * Exception processor for exceptions detected from the parser. (This is invoked by the parser
    334      * when an error is detected).
    335      *
    336      * @param sipMessage -- the message that incurred the error.
    337      * @param ex -- parse exception detected by the parser.
    338      * @param header -- header that caused the error.
    339      * @throws ParseException Thrown if we want to reject the message.
    340      */
    341     public void handleException(ParseException ex, SIPMessage sipMessage, Class hdrClass,
    342             String header, String message) throws ParseException {
    343         if (sipStack.isLoggingEnabled())
    344             sipStack.getStackLogger().logException(ex);
    345         // Log the bad message for later reference.
    346         if ((hdrClass != null)
    347                 && (hdrClass.equals(From.class) || hdrClass.equals(To.class)
    348                         || hdrClass.equals(CSeq.class) || hdrClass.equals(Via.class)
    349                         || hdrClass.equals(CallID.class) || hdrClass.equals(RequestLine.class) || hdrClass
    350                         .equals(StatusLine.class))) {
    351         	if (sipStack.isLoggingEnabled())
    352         		sipStack.getStackLogger().logDebug("Encountered bad message \n" + message);
    353             // JvB: send a 400 response for requests (except ACK)
    354             String msgString = sipMessage.toString();
    355             if (!msgString.startsWith("SIP/") && !msgString.startsWith("ACK ")) {
    356 
    357                 String badReqRes = createBadReqRes(msgString, ex);
    358                 if (badReqRes != null) {
    359                     if (sipStack.isLoggingEnabled()) {
    360                         sipStack.getStackLogger().logDebug("Sending automatic 400 Bad Request:");
    361                         sipStack.getStackLogger().logDebug(badReqRes);
    362                     }
    363                     try {
    364                         this.sendMessage(badReqRes.getBytes(), this.getPeerInetAddress(), this
    365                                 .getPeerPort(), false);
    366                     } catch (IOException e) {
    367                         this.sipStack.getStackLogger().logException(e);
    368                     }
    369                 } else {
    370                     if (sipStack.isLoggingEnabled()) {
    371                         sipStack.getStackLogger().logDebug(
    372                                 "Could not formulate automatic 400 Bad Request");
    373                     }
    374                 }
    375             }
    376             throw ex;
    377         } else {
    378             sipMessage.addUnparsed(header);
    379         }
    380     }
    381 
    382     /**
    383      * Gets invoked by the parser as a callback on successful message parsing (i.e. no parser
    384      * errors).
    385      *
    386      * @param sipMessage Message to process (this calls the application for processing the
    387      *        message).
    388      *
    389      * Jvb: note that this code is identical to TCPMessageChannel, refactor some day
    390      */
    391     public void processMessage(SIPMessage sipMessage) throws Exception {
    392         try {
    393             if (sipMessage.getFrom() == null || sipMessage.getTo() == null
    394                     || sipMessage.getCallId() == null || sipMessage.getCSeq() == null
    395                     || sipMessage.getViaHeaders() == null) {
    396                 String badmsg = sipMessage.encode();
    397                 if (sipStack.isLoggingEnabled()) {
    398                     sipStack.getStackLogger().logError("bad message " + badmsg);
    399                     sipStack.getStackLogger().logError(">>> Dropped Bad Msg");
    400                 }
    401                 return;
    402             }
    403 
    404             ViaList viaList = sipMessage.getViaHeaders();
    405             // For a request
    406             // first via header tells where the message is coming from.
    407             // For response, this has already been recorded in the outgoing
    408             // message.
    409 
    410             if (sipMessage instanceof SIPRequest) {
    411                 Via v = (Via) viaList.getFirst();
    412                 // the peer address and tag it appropriately.
    413                 Hop hop = sipStack.addressResolver.resolveAddress(v.getHop());
    414                 this.peerProtocol = v.getTransport();
    415                 try {
    416                     this.peerAddress = mySock.getInetAddress();
    417                     // Check to see if the received parameter matches
    418                     // JvB: dont do this. It is both costly and incorrect
    419                     // Must set received also when it is a FQDN, regardless whether
    420                     // it resolves to the correct IP address
    421                     // InetAddress sentByAddress = InetAddress.getByName(hop.getHost());
    422                     // JvB: if sender added 'rport', must always set received
    423                     if (v.hasParameter(Via.RPORT)
    424                             || !hop.getHost().equals(this.peerAddress.getHostAddress())) {
    425                         v.setParameter(Via.RECEIVED, this.peerAddress.getHostAddress());
    426                     }
    427                     // @@@ hagai
    428                     // JvB: technically, may only do this when Via already contains
    429                     // rport
    430                     v.setParameter(Via.RPORT, Integer.toString(this.peerPort));
    431                 } catch (java.text.ParseException ex) {
    432                     InternalErrorHandler.handleException(ex);
    433                 }
    434                 // Use this for outgoing messages as well.
    435                 if (!this.isCached) {
    436                     ((TLSMessageProcessor) this.messageProcessor).cacheMessageChannel(this);
    437                     this.isCached = true;
    438                     String key = IOHandler.makeKey(mySock.getInetAddress(), this.peerPort);
    439                     sipStack.ioHandler.putSocket(key, mySock);
    440                 }
    441             }
    442 
    443             // Foreach part of the request header, fetch it and process it
    444 
    445             long receptionTime = System.currentTimeMillis();
    446             //
    447 
    448             if (sipMessage instanceof SIPRequest) {
    449                 // This is a request - process the request.
    450                 SIPRequest sipRequest = (SIPRequest) sipMessage;
    451                 // Create a new sever side request processor for this
    452                 // message and let it handle the rest.
    453 
    454                 if (sipStack.isLoggingEnabled()) {
    455                     sipStack.getStackLogger().logDebug("----Processing Message---");
    456                 }
    457                 if (this.sipStack.getStackLogger().isLoggingEnabled(ServerLogger.TRACE_MESSAGES)) {
    458 
    459                     sipStack.serverLogger.logMessage(sipMessage, this.getPeerHostPort().toString(),
    460                             this.messageProcessor.getIpAddress().getHostAddress() + ":"
    461                                     + this.messageProcessor.getPort(), false, receptionTime);
    462 
    463                 }
    464                 // Check for reasonable size - reject message
    465                 // if it is too long.
    466                 if (sipStack.getMaxMessageSize() > 0
    467                         && sipRequest.getSize()
    468                                 + (sipRequest.getContentLength() == null ? 0 : sipRequest
    469                                         .getContentLength().getContentLength()) > sipStack
    470                                 .getMaxMessageSize()) {
    471                     SIPResponse sipResponse = sipRequest
    472                             .createResponse(SIPResponse.MESSAGE_TOO_LARGE);
    473                     byte[] resp = sipResponse.encodeAsBytes(this.getTransport());
    474                     this.sendMessage(resp, false);
    475                     throw new Exception("Message size exceeded");
    476                 }
    477 
    478                 // Stack could not create a new server request interface.
    479                 // maybe not enough resources.
    480                 ServerRequestInterface sipServerRequest = sipStack.newSIPServerRequest(
    481                         sipRequest, this);
    482                 if (sipServerRequest != null) {
    483                     try {
    484                         sipServerRequest.processRequest(sipRequest, this);
    485                     } finally {
    486                         if (sipServerRequest instanceof SIPTransaction) {
    487                             SIPServerTransaction sipServerTx = (SIPServerTransaction) sipServerRequest;
    488                             if (!sipServerTx.passToListener())
    489                                 ((SIPTransaction) sipServerRequest).releaseSem();
    490                         }
    491                     }
    492                 } else {
    493                     SIPResponse response = sipRequest
    494                             .createResponse(Response.SERVICE_UNAVAILABLE);
    495 
    496                     RetryAfter retryAfter = new RetryAfter();
    497 
    498                     // Be a good citizen and send a decent response code back.
    499                     try {
    500                         retryAfter.setRetryAfter((int) (10 * (Math.random())));
    501                         response.setHeader(retryAfter);
    502                         this.sendMessage(response);
    503                     } catch (Exception e) {
    504                         // IGNore
    505                     }
    506                     if (sipStack.isLoggingEnabled())
    507                     	sipStack.getStackLogger()
    508                             .logWarning("Dropping message -- could not acquire semaphore");
    509                 }
    510             } else {
    511                 SIPResponse sipResponse = (SIPResponse) sipMessage;
    512                 try {
    513                     sipResponse.checkHeaders();
    514                 } catch (ParseException ex) {
    515                     if (sipStack.isLoggingEnabled())
    516                         sipStack.getStackLogger()
    517                                 .logError("Dropping Badly formatted response message >>> "
    518                                         + sipResponse);
    519                     return;
    520                 }
    521                 // This is a response message - process it.
    522                 // Check the size of the response.
    523                 // If it is too large dump it silently.
    524                 if (sipStack.getMaxMessageSize() > 0
    525                         && sipResponse.getSize()
    526                                 + (sipResponse.getContentLength() == null ? 0 : sipResponse
    527                                         .getContentLength().getContentLength()) > sipStack
    528                                 .getMaxMessageSize()) {
    529                     if (sipStack.isLoggingEnabled())
    530                         this.sipStack.getStackLogger().logDebug("Message size exceeded");
    531                     return;
    532 
    533                 }
    534                 ServerResponseInterface sipServerResponse = sipStack.newSIPServerResponse(
    535                         sipResponse, this);
    536                 if (sipServerResponse != null) {
    537                     try {
    538                         if (sipServerResponse instanceof SIPClientTransaction
    539                                 && !((SIPClientTransaction) sipServerResponse)
    540                                         .checkFromTag(sipResponse)) {
    541                             if (sipStack.isLoggingEnabled())
    542                                 sipStack.getStackLogger()
    543                                         .logError("Dropping response message with invalid tag >>> "
    544                                                 + sipResponse);
    545                             return;
    546                         }
    547 
    548                         sipServerResponse.processResponse(sipResponse, this);
    549                     } finally {
    550                         if (sipServerResponse instanceof SIPTransaction
    551                                 && !((SIPTransaction) sipServerResponse).passToListener()) {
    552                             // Note that the semaphore is released in event
    553                             // scanner if the
    554                             // request is actually processed by the Listener.
    555                             ((SIPTransaction) sipServerResponse).releaseSem();
    556                         }
    557                     }
    558                 } else {
    559                     sipStack.getStackLogger().logWarning("Could not get semaphore... dropping response");
    560                 }
    561             }
    562         } finally {
    563         }
    564     }
    565 
    566     /**
    567      * This gets invoked when thread.start is called from the constructor. Implements a message
    568      * loop - reading the tcp connection and processing messages until we are done or the other
    569      * end has closed.
    570      */
    571     public void run() {
    572         Pipeline hispipe = null;
    573         // Create a pipeline to connect to our message parser.
    574         hispipe = new Pipeline(myClientInputStream, sipStack.readTimeout,
    575                 ((SIPTransactionStack) sipStack).getTimer());
    576         // Create a pipelined message parser to read and parse
    577         // messages that we write out to him.
    578         myParser = new PipelinedMsgParser(this, hispipe, this.sipStack.getMaxMessageSize());
    579         // Start running the parser thread.
    580         myParser.processInput();
    581         // bug fix by Emmanuel Proulx
    582         int bufferSize = 4096;
    583         this.tlsMessageProcessor.useCount++;
    584         this.isRunning = true;
    585         try {
    586             while (true) {
    587                 try {
    588                     byte[] msg = new byte[bufferSize];
    589                     int nbytes = myClientInputStream.read(msg, 0, bufferSize);
    590                     // no more bytes to read...
    591                     if (nbytes == -1) {
    592                         hispipe.write("\r\n\r\n".getBytes("UTF-8"));
    593                         try {
    594                             if (sipStack.maxConnections != -1) {
    595                                 synchronized (tlsMessageProcessor) {
    596                                     tlsMessageProcessor.nConnections--;
    597                                     tlsMessageProcessor.notify();
    598                                 }
    599                             }
    600                             hispipe.close();
    601                             mySock.close();
    602                         } catch (IOException ioex) {
    603                         }
    604                         return;
    605                     }
    606                     hispipe.write(msg, 0, nbytes);
    607 
    608                 } catch (IOException ex) {
    609                     // Terminate the message.
    610                     try {
    611                         hispipe.write("\r\n\r\n".getBytes("UTF-8"));
    612                     } catch (Exception e) {
    613                         // InternalErrorHandler.handleException(e);
    614                     }
    615 
    616                     try {
    617                         if (sipStack.isLoggingEnabled())
    618                             sipStack.getStackLogger().logDebug("IOException  closing sock " + ex);
    619                         try {
    620                             if (sipStack.maxConnections != -1) {
    621                                 synchronized (tlsMessageProcessor) {
    622                                     tlsMessageProcessor.nConnections--;
    623                                     tlsMessageProcessor.notify();
    624                                 }
    625                             }
    626                             mySock.close();
    627                             hispipe.close();
    628                         } catch (IOException ioex) {
    629                         }
    630                     } catch (Exception ex1) {
    631                         // Do nothing.
    632                     }
    633                     return;
    634                 } catch (Exception ex) {
    635                     InternalErrorHandler.handleException(ex);
    636                 }
    637             }
    638         } finally {
    639             this.isRunning = false;
    640             this.tlsMessageProcessor.remove(this);
    641             this.tlsMessageProcessor.useCount--;
    642             this.myParser.close();
    643         }
    644 
    645     }
    646 
    647     protected void uncache() {
    648     	if (isCached && !isRunning) {
    649     		this.tlsMessageProcessor.remove(this);
    650     	}
    651     }
    652 
    653     /**
    654      * Equals predicate.
    655      *
    656      * @param other is the other object to compare ourselves to for equals
    657      */
    658 
    659     public boolean equals(Object other) {
    660 
    661         if (!this.getClass().equals(other.getClass()))
    662             return false;
    663         else {
    664             TLSMessageChannel that = (TLSMessageChannel) other;
    665             if (this.mySock != that.mySock)
    666                 return false;
    667             else
    668                 return true;
    669         }
    670     }
    671 
    672     /**
    673      * Get an identifying key. This key is used to cache the connection and re-use it if
    674      * necessary.
    675      */
    676     public String getKey() {
    677         if (this.key != null) {
    678             return this.key;
    679         } else {
    680             this.key = MessageChannel.getKey(this.peerAddress, this.peerPort, "TLS");
    681             return this.key;
    682         }
    683     }
    684 
    685     /**
    686      * Get the host to assign to outgoing messages.
    687      *
    688      * @return the host to assign to the via header.
    689      */
    690     public String getViaHost() {
    691         return myAddress;
    692     }
    693 
    694     /**
    695      * Get the port for outgoing messages sent from the channel.
    696      *
    697      * @return the port to assign to the via header.
    698      */
    699     public int getViaPort() {
    700         return myPort;
    701     }
    702 
    703     /**
    704      * Get the port of the peer to whom we are sending messages.
    705      *
    706      * @return the peer port.
    707      */
    708     public int getPeerPort() {
    709         return peerPort;
    710     }
    711 
    712     public int getPeerPacketSourcePort() {
    713         return this.peerPort;
    714     }
    715 
    716     public InetAddress getPeerPacketSourceAddress() {
    717         return this.peerAddress;
    718     }
    719 
    720     /**
    721      * TLS Is a secure protocol.
    722      */
    723     public boolean isSecure() {
    724         return true;
    725     }
    726 
    727     public void setHandshakeCompletedListener(
    728             HandshakeCompletedListener handshakeCompletedListenerImpl) {
    729         this.handshakeCompletedListener = handshakeCompletedListenerImpl;
    730     }
    731 
    732     /**
    733      * @return the handshakeCompletedListener
    734      */
    735     public HandshakeCompletedListenerImpl getHandshakeCompletedListener() {
    736         return (HandshakeCompletedListenerImpl) handshakeCompletedListener;
    737     }
    738 }
    739