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