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