• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@dif.um.es>
28  * made these changes. Ahmet Uyar
29  * <auyar@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@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 
TLSMessageChannel(Socket sock, SIPTransactionStack sipStack, TLSMessageProcessor msgProcessor)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      */
TLSMessageChannel(InetAddress inetAddr, int port, SIPTransactionStack sipStack, TLSMessageProcessor messageProcessor)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      */
isReliable()190     public boolean isReliable() {
191         return true;
192     }
193 
194     /**
195      * Close the message channel.
196      */
close()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      */
getSIPStack()214     public SIPTransactionStack getSIPStack() {
215         return sipStack;
216     }
217 
218     /**
219      * get the transport string.
220      *
221      * @return "tcp" in this case.
222      */
getTransport()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      */
getPeerAddress()233     public String getPeerAddress() {
234         if (peerAddress != null) {
235             return peerAddress.getHostAddress();
236         } else
237             return getHost();
238     }
239 
getPeerInetAddress()240     protected InetAddress getPeerInetAddress() {
241         return peerAddress;
242     }
243 
getPeerProtocol()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      */
sendMessage(byte[] msg, boolean retry)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      */
sendMessage(SIPMessage sipMessage)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      */
sendMessage(byte message[], InetAddress receiverAddress, int receiverPort, boolean retry)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      */
handleException(ParseException ex, SIPMessage sipMessage, Class hdrClass, String header, String message)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      */
processMessage(SIPMessage sipMessage)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      */
run()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 
uncache()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 
equals(Object other)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      */
getKey()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      */
getViaHost()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      */
getViaPort()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      */
getPeerPort()708     public int getPeerPort() {
709         return peerPort;
710     }
711 
getPeerPacketSourcePort()712     public int getPeerPacketSourcePort() {
713         return this.peerPort;
714     }
715 
getPeerPacketSourceAddress()716     public InetAddress getPeerPacketSourceAddress() {
717         return this.peerAddress;
718     }
719 
720     /**
721      * TLS Is a secure protocol.
722      */
isSecure()723     public boolean isSecure() {
724         return true;
725     }
726 
setHandshakeCompletedListener( HandshakeCompletedListener handshakeCompletedListenerImpl)727     public void setHandshakeCompletedListener(
728             HandshakeCompletedListener handshakeCompletedListenerImpl) {
729         this.handshakeCompletedListener = handshakeCompletedListenerImpl;
730     }
731 
732     /**
733      * @return the handshakeCompletedListener
734      */
getHandshakeCompletedListener()735     public HandshakeCompletedListenerImpl getHandshakeCompletedListener() {
736         return (HandshakeCompletedListenerImpl) handshakeCompletedListener;
737     }
738 }
739