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 /******************************************************************************
     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 (at) 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 (at) 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 
    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 
    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      */
    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      */
    176     public boolean isReliable() {
    177         return true;
    178     }
    179 
    180     /**
    181      * Close the message channel.
    182      */
    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      */
    202     public SIPTransactionStack getSIPStack() {
    203         return sipStack;
    204     }
    205 
    206     /**
    207      * get the transport string.
    208      *
    209      * @return "tcp" in this case.
    210      */
    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      */
    221     public String getPeerAddress() {
    222         if (peerAddress != null) {
    223             return peerAddress.getHostAddress();
    224         } else
    225             return getHost();
    226     }
    227 
    228     protected InetAddress getPeerInetAddress() {
    229         return peerAddress;
    230     }
    231 
    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      */
    242     private void sendMessage(byte[] msg, boolean retry) throws IOException {
    243 
    244         /*
    245          * Patch from kircuv (at) 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      */
    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      */
    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      */
    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      */
    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      */
    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 
    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 
    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      */
    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      */
    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      */
    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      */
    729     public int getPeerPort() {
    730         return peerPort;
    731     }
    732 
    733     public int getPeerPacketSourcePort() {
    734         return this.peerPort;
    735     }
    736 
    737     public InetAddress getPeerPacketSourceAddress() {
    738         return this.peerAddress;
    739     }
    740 
    741     /**
    742      * TCP Is not a secure protocol.
    743      */
    744     public boolean isSecure() {
    745         return false;
    746     }
    747 }
    748