Home | History | Annotate | Download | only in stack
      1 /*
      2  * Conditions Of Use
      3  *
      4  * This software was developed by employees of the National Institute of
      5  * Standards and Technology (NIST), an agency of the Federal Government.
      6  * Pursuant to title 15 Untied States Code Section 105, works of NIST
      7  * employees are not subject to copyright protection in the United States
      8  * and are considered to be in the public domain.  As a result, a formal
      9  * license is not needed to use the software.
     10  *
     11  * This software is provided by NIST as a service and is expressly
     12  * provided "AS IS."  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
     13  * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
     14  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
     15  * AND DATA ACCURACY.  NIST does not warrant or make any representations
     16  * regarding the use of the software or the results thereof, including but
     17  * not limited to the correctness, accuracy, reliability or usefulness of
     18  * the software.
     19  *
     20  * Permission to use this software is contingent upon your acceptance
     21  * of the terms of this agreement
     22  *
     23  * .
     24  *
     25  */
     26 /* This class is entirely derived from TCPMessageProcessor,
     27  *  by making some minor changes.
     28  *
     29  *               Daniel J. Martinez Manzano <dani (at) dif.um.es>
     30  * Acknowledgement: Jeff Keyser suggested that a
     31  * Stop mechanism be added to this. Niklas Uhrberg suggested that
     32  * a means to limit the number of simultaneous active connections
     33  * should be added. Mike Andrews suggested that the thread be
     34  * accessible so as to implement clean stop using Thread.join().
     35  *
     36  */
     37 
     38 /******************************************************************************
     39  * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).      *
     40  ******************************************************************************/
     41 package gov.nist.javax.sip.stack;
     42 
     43 import gov.nist.core.HostPort;
     44 import gov.nist.javax.sip.SipStackImpl;
     45 
     46 import javax.net.ssl.SSLException;
     47 import javax.net.ssl.SSLServerSocket;
     48 import javax.net.ssl.SSLSocket;
     49 
     50 import java.io.IOException;
     51 import java.net.*;
     52 import java.util.ArrayList;
     53 import java.util.Collection;
     54 import java.util.Hashtable;
     55 import java.util.Iterator;
     56 
     57 /**
     58  * Sit in a loop waiting for incoming tls connections and start a new thread to handle each new
     59  * connection. This is the active object that creates new TLS MessageChannels (one for each new
     60  * accept socket).
     61  *
     62  * @version 1.2 $Revision: 1.23 $ $Date: 2009/12/06 15:58:39 $
     63  *
     64  * @author M. Ranganathan <br/>
     65  *
     66  */
     67 public class TLSMessageProcessor extends MessageProcessor {
     68 
     69     protected int nConnections;
     70 
     71     private boolean isRunning;
     72 
     73     private Hashtable<String, TLSMessageChannel> tlsMessageChannels;
     74 
     75     private ServerSocket sock;
     76 
     77     protected int useCount = 0;
     78 
     79     private ArrayList<TLSMessageChannel> incomingTlsMessageChannels;
     80 
     81     /**
     82      * Constructor.
     83      *
     84      * @param ipAddress -- inet address where I am listening.
     85      * @param sipStack SIPStack structure.
     86      * @param port port where this message processor listens.
     87      */
     88     protected TLSMessageProcessor(InetAddress ipAddress, SIPTransactionStack sipStack, int port) {
     89         super(ipAddress, port, "tls",sipStack);
     90         this.sipStack = sipStack;
     91         this.tlsMessageChannels = new Hashtable<String, TLSMessageChannel>();
     92         this.incomingTlsMessageChannels = new ArrayList<TLSMessageChannel>();
     93 
     94     }
     95 
     96     /**
     97      * Start the processor.
     98      */
     99     public void start() throws IOException {
    100         Thread thread = new Thread(this);
    101         thread.setName("TLSMessageProcessorThread");
    102         // ISSUE 184
    103         thread.setPriority(Thread.MAX_PRIORITY);
    104         thread.setDaemon(true);
    105 
    106         this.sock = sipStack.getNetworkLayer().createSSLServerSocket(this.getPort(), 0,
    107                 this.getIpAddress());
    108         ((SSLServerSocket) this.sock).setNeedClientAuth(false);
    109         ((SSLServerSocket) this.sock).setUseClientMode(false);
    110         ((SSLServerSocket) this.sock).setWantClientAuth(true);
    111         String []enabledCiphers = ((SipStackImpl)sipStack).getEnabledCipherSuites();
    112         ((SSLServerSocket) this.sock).setEnabledCipherSuites(enabledCiphers);
    113         ((SSLServerSocket)this.sock).setWantClientAuth(true);
    114 
    115 
    116         this.isRunning = true;
    117         thread.start();
    118 
    119     }
    120 
    121     /**
    122      * Run method for the thread that gets created for each accept socket.
    123      */
    124     public void run() {
    125         // Accept new connectins on our socket.
    126         while (this.isRunning) {
    127             try {
    128                 synchronized (this) {
    129                     // sipStack.maxConnections == -1 means we are
    130                     // willing to handle an "infinite" number of
    131                     // simultaneous connections (no resource limitation).
    132                     // This is the default behavior.
    133                     while (sipStack.maxConnections != -1
    134                             && this.nConnections >= sipStack.maxConnections) {
    135                         try {
    136                             this.wait();
    137 
    138                             if (!this.isRunning)
    139                                 return;
    140                         } catch (InterruptedException ex) {
    141                             break;
    142                         }
    143                     }
    144                     this.nConnections++;
    145                 }
    146 
    147                 Socket newsock = sock.accept();
    148 
    149                 if (sipStack.isLoggingEnabled())
    150                     sipStack.getStackLogger().logDebug("Accepting new connection!");
    151 
    152 
    153                // Note that for an incoming message channel, the
    154                // thread is already running
    155 
    156                 incomingTlsMessageChannels.add(new TLSMessageChannel(newsock, sipStack, this));
    157             } catch (SocketException ex) {
    158                 if ( this.isRunning ) {
    159                   sipStack.getStackLogger().logError(
    160                     "Fatal - SocketException occured while Accepting connection", ex);
    161                   this.isRunning = false;
    162                   break;
    163                 }
    164             } catch (SSLException ex) {
    165                 this.isRunning = false;
    166                 sipStack.getStackLogger().logError(
    167                         "Fatal - SSSLException occured while Accepting connection", ex);
    168                 break;
    169             } catch (IOException ex) {
    170                 // Problem accepting connection.
    171                 sipStack.getStackLogger().logError("Problem Accepting Connection", ex);
    172                 continue;
    173             } catch (Exception ex) {
    174                 sipStack.getStackLogger().logError("Unexpected Exception!", ex);
    175             }
    176         }
    177     }
    178 
    179     /**
    180      * Returns the stack.
    181      *
    182      * @return my sip stack.
    183      */
    184     public SIPTransactionStack getSIPStack() {
    185         return sipStack;
    186     }
    187 
    188     /**
    189      * Stop the message processor. Feature suggested by Jeff Keyser.
    190      */
    191     public synchronized void stop() {
    192         if (!isRunning)
    193             return;
    194 
    195         isRunning = false;
    196         try {
    197             sock.close();
    198         } catch (IOException e) {
    199             e.printStackTrace();
    200         }
    201 
    202         Collection en = tlsMessageChannels.values();
    203         for (Iterator it = en.iterator(); it.hasNext();) {
    204             TLSMessageChannel next = (TLSMessageChannel) it.next();
    205             next.close();
    206         }
    207         for (Iterator incomingMCIterator = incomingTlsMessageChannels.iterator(); incomingMCIterator
    208                 .hasNext();) {
    209             TLSMessageChannel next = (TLSMessageChannel) incomingMCIterator.next();
    210             next.close();
    211         }
    212         this.notify();
    213 
    214     }
    215 
    216     protected synchronized void remove(TLSMessageChannel tlsMessageChannel) {
    217 
    218         String key = tlsMessageChannel.getKey();
    219         if (sipStack.isLoggingEnabled()) {
    220             sipStack.getStackLogger().logDebug(Thread.currentThread() + " removing " + key);
    221         }
    222 
    223         /** May have been removed already */
    224         if (tlsMessageChannels.get(key) == tlsMessageChannel)
    225             this.tlsMessageChannels.remove(key);
    226 
    227         incomingTlsMessageChannels.remove(tlsMessageChannel);
    228     }
    229 
    230     public synchronized MessageChannel createMessageChannel(HostPort targetHostPort)
    231             throws IOException {
    232         String key = MessageChannel.getKey(targetHostPort, "TLS");
    233         if (tlsMessageChannels.get(key) != null) {
    234             return (TLSMessageChannel) this.tlsMessageChannels.get(key);
    235         } else {
    236             TLSMessageChannel retval = new TLSMessageChannel(targetHostPort.getInetAddress(),
    237                     targetHostPort.getPort(), sipStack, this);
    238             this.tlsMessageChannels.put(key, retval);
    239             retval.isCached = true;
    240             if (sipStack.isLoggingEnabled()) {
    241                 sipStack.getStackLogger().logDebug("key " + key);
    242                 sipStack.getStackLogger().logDebug("Creating " + retval);
    243             }
    244             return retval;
    245         }
    246     }
    247 
    248     protected synchronized void cacheMessageChannel(TLSMessageChannel messageChannel) {
    249         String key = messageChannel.getKey();
    250         TLSMessageChannel currentChannel = (TLSMessageChannel) tlsMessageChannels.get(key);
    251         if (currentChannel != null) {
    252             if (sipStack.isLoggingEnabled())
    253                 sipStack.getStackLogger().logDebug("Closing " + key);
    254             currentChannel.close();
    255         }
    256         if (sipStack.isLoggingEnabled())
    257             sipStack.getStackLogger().logDebug("Caching " + key);
    258         this.tlsMessageChannels.put(key, messageChannel);
    259 
    260     }
    261 
    262     public synchronized MessageChannel createMessageChannel(InetAddress host, int port)
    263             throws IOException {
    264         try {
    265             String key = MessageChannel.getKey(host, port, "TLS");
    266             if (tlsMessageChannels.get(key) != null) {
    267                 return (TLSMessageChannel) this.tlsMessageChannels.get(key);
    268             } else {
    269                 TLSMessageChannel retval = new TLSMessageChannel(host, port, sipStack, this);
    270                 this.tlsMessageChannels.put(key, retval);
    271                 retval.isCached = true;
    272                 if (sipStack.isLoggingEnabled()) {
    273                     sipStack.getStackLogger().logDebug("key " + key);
    274                     sipStack.getStackLogger().logDebug("Creating " + retval);
    275                 }
    276                 return retval;
    277             }
    278         } catch (UnknownHostException ex) {
    279             throw new IOException(ex.getMessage());
    280         }
    281     }
    282 
    283     /**
    284      * TLS can handle an unlimited number of bytes.
    285      */
    286     public int getMaximumMessageSize() {
    287         return Integer.MAX_VALUE;
    288     }
    289 
    290     public boolean inUse() {
    291         return this.useCount != 0;
    292     }
    293 
    294     /**
    295      * Default target port for TLS
    296      */
    297     public int getDefaultTargetPort() {
    298         return 5061;
    299     }
    300 
    301     /**
    302      * TLS is a secure protocol.
    303      */
    304     public boolean isSecure() {
    305         return true;
    306     }
    307 }
    308