1 22 package org.xsocket.stream.io.impl; 23 24 import java.io.IOException ; 25 import java.nio.ByteBuffer ; 26 import java.util.LinkedList ; 27 import java.util.List ; 28 import java.util.logging.Level ; 29 import java.util.logging.Logger ; 30 31 import javax.net.ssl.SSLContext; 32 import javax.net.ssl.SSLEngine; 33 import javax.net.ssl.SSLEngineResult; 34 import javax.net.ssl.SSLException; 35 import javax.net.ssl.SSLEngineResult.HandshakeStatus; 36 37 38 import org.xsocket.ClosedConnectionException; 39 import org.xsocket.DataConverter; 40 41 42 43 48 final class SSLProcessor { 49 50 private static final Logger LOG = Logger.getLogger(SSLProcessor.class.getName()); 51 52 53 private SSLEngine sslEngine = null; 54 55 private boolean isClientMode = false; 56 private IMemoryManager memoryManager = null; 57 private EventHandler eventHandler = null; 58 59 private int minNetBufferSize = 0; 61 private int minAppBufferSize = 0; 62 63 64 70 SSLProcessor(SSLContext sslContext, boolean isClientMode, IMemoryManager memoryManager, EventHandler eventHandler) { 71 this.isClientMode = isClientMode; 72 this.memoryManager = memoryManager; 73 this.eventHandler = eventHandler; 74 75 sslEngine = sslContext.createSSLEngine(); 76 minAppBufferSize = sslEngine.getSession().getApplicationBufferSize(); 77 minNetBufferSize = sslEngine.getSession().getPacketBufferSize(); 78 79 sslEngine.setUseClientMode(isClientMode); 80 } 81 82 83 84 90 synchronized void start() throws IOException { 91 try { 92 sslEngine.beginHandshake(); 93 } catch (SSLException sslEx) { 94 throw new RuntimeException (sslEx); 95 } 96 97 98 if (isClientMode) { 99 if (LOG.isLoggable(Level.FINE)) { 100 LOG.fine("initate ssl handshake"); 101 } 102 processOutAppData(); 103 } 104 } 105 106 107 111 void destroy() { 112 sslEngine.closeOutbound(); 113 } 114 115 116 123 synchronized void processInNetData(LinkedList <ByteBuffer > inNetBufferList) throws IOException ,ClosedConnectionException { 124 125 LinkedList <ByteBuffer > inAppDataList = new LinkedList <ByteBuffer >(); 126 127 try { 128 int size = 0; 129 for (ByteBuffer buffer : inNetBufferList) { 130 size += buffer.remaining(); 131 } 132 133 for (ByteBuffer inNetBuffer : inNetBufferList) { 134 List <ByteBuffer > inAppData = unwrap(inNetBuffer); 135 inAppDataList.addAll(inAppData); 136 137 138 if (LOG.isLoggable(Level.FINE)) { 139 int appDataSize = 0; 140 ByteBuffer [] inAppDataListCopy = new ByteBuffer [inAppDataList.size()]; 141 for (int i = 0; i < inAppDataList.size(); i++) { 142 appDataSize += inAppDataList.get(i).remaining(); 143 inAppDataListCopy[i] = inAppDataList.get(i).duplicate(); 144 } 145 146 if ((size - appDataSize) > 0) { 147 LOG.fine((size - appDataSize) + " ssl system packet data "); 148 } 149 150 if (appDataSize > 0) { 151 LOG.fine(appDataSize + " app data extracted: " + DataConverter.toTextOrHexString(inAppDataListCopy, "UTF-8", 500)); 152 } 153 } 154 } 155 156 if (!inAppDataList.isEmpty()) { 157 eventHandler.onInAppDataReceived(inAppDataList); 158 } 159 } catch (SSLException sslEx) { 160 eventHandler.onSSLProcessorClosed(); 161 } 162 163 164 if (sslEngine.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_WRAP) { 165 processOutAppData(); 166 } 167 } 168 169 170 175 synchronized boolean isHandshaking() { 176 HandshakeStatus handshakeStatus = sslEngine.getHandshakeStatus(); 177 return !(handshakeStatus == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) 178 || (handshakeStatus == SSLEngineResult.HandshakeStatus.FINISHED); 179 } 180 181 182 189 void processOutAppData(LinkedList <ByteBuffer > outAppDataList) throws ClosedConnectionException, IOException { 190 for (ByteBuffer outAppData : outAppDataList) { 191 wrap(outAppData); 192 } 193 } 194 195 201 void processOutAppData() throws ClosedConnectionException, IOException { 202 ByteBuffer outAppData = ByteBuffer.allocate(0); 203 wrap(outAppData); 204 } 205 206 207 private synchronized LinkedList <ByteBuffer > unwrap(ByteBuffer inNetData) throws SSLException, ClosedConnectionException, IOException { 208 LinkedList <ByteBuffer > inAppDataList = new LinkedList <ByteBuffer >(); 209 int minAppSize = minAppBufferSize; 210 211 try { 212 do { 213 214 ByteBuffer inAppData = memoryManager.acquireMemory(minAppSize); 216 SSLEngineResult engineResult = sslEngine.unwrap(inNetData, inAppData); 217 218 219 if ((engineResult.getStatus() == SSLEngineResult.Status.OK) 221 || (engineResult.getStatus() == SSLEngineResult.Status.BUFFER_UNDERFLOW)) { 222 223 if (inNetData.position() < inNetData.limit()) { 225 inNetData = inNetData.slice(); 226 } 227 228 inAppData.flip(); 230 inAppData = extractAndRecycleMemory(inAppData, minAppSize); 231 if (inAppData.remaining() > 0) { 232 inAppDataList.add(inAppData); 233 } 234 235 236 } else if (engineResult.getStatus() == SSLEngineResult.Status.BUFFER_OVERFLOW) { 237 memoryManager.recycleMemory(inAppData, minAppSize); 239 minAppSize += minAppSize; 240 continue; 241 242 243 } else if (engineResult.getStatus() == SSLEngineResult.Status.CLOSED) { 244 memoryManager.recycleMemory(inAppData, minAppSize); 245 throw new ClosedConnectionException("Couldn't unwrap, because connection is closed"); 246 } 247 248 249 250 if (sslEngine.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_TASK) { 252 Runnable task = null; 253 while ((task = sslEngine.getDelegatedTask()) != null) { 254 task.run(); 255 } 256 } 257 258 259 if (engineResult.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.FINISHED) { 261 notifyHandshakeFinished(); 262 } 263 264 265 } while (inNetData.hasRemaining()); 266 267 } catch (SSLException ssles) { 268 throw ssles; 269 } 270 271 return inAppDataList; 272 } 273 274 275 276 private synchronized void wrap(ByteBuffer outAppData) throws SSLException, ClosedConnectionException, IOException { 277 int minNetSize = minNetBufferSize; 278 279 do { 280 281 ByteBuffer outNetData = memoryManager.acquireMemory(minNetSize); 283 SSLEngineResult engineResult = sslEngine.wrap(outAppData, outNetData); 284 285 286 if ((engineResult.getStatus() == SSLEngineResult.Status.OK) 288 || (engineResult.getStatus() == SSLEngineResult.Status.BUFFER_UNDERFLOW)) { 289 290 if (outAppData.position() < outAppData.limit()) { 292 outAppData = outAppData.slice(); 293 } 294 295 outNetData.flip(); 297 outNetData = extractAndRecycleMemory(outNetData, minNetSize); 298 if (outNetData.hasRemaining()) { 299 eventHandler.onOutNetDataToWrite(outNetData); 300 } 301 302 303 } else if (engineResult.getStatus() == SSLEngineResult.Status.BUFFER_OVERFLOW) { 304 memoryManager.recycleMemory(outNetData, minNetSize); 306 minNetSize += minNetSize; 307 continue; 308 309 310 } else if (engineResult.getStatus() == SSLEngineResult.Status.CLOSED) { 311 memoryManager.recycleMemory(outNetData, minNetSize); 312 throw new ClosedConnectionException("Couldn't wrap, because connection is closed"); 313 } 314 315 316 if (sslEngine.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_TASK) { 318 Runnable task = null; 319 while ((task = sslEngine.getDelegatedTask()) != null) { 320 task.run(); 321 } 322 } 323 324 325 if (engineResult.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.FINISHED) { 327 notifyHandshakeFinished(); 328 break; 329 } 330 } while (outAppData.hasRemaining() || (sslEngine.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_WRAP)); 331 332 } 333 334 335 private void notifyHandshakeFinished() throws IOException { 336 if (LOG.isLoggable(Level.FINE)) { 337 if (isClientMode) { 338 LOG.fine("handshake has been finished (clientMode)"); 339 } else { 340 LOG.fine("handshake has been finished (serverMode)"); 341 } 342 } 343 344 processOutAppData(); 345 eventHandler.onHandshakeFinished(); 346 } 347 348 349 private ByteBuffer extractAndRecycleMemory(ByteBuffer buffer, int minSize) { 350 if (buffer.limit() == buffer.capacity()) { 352 return buffer; 353 354 } else { 356 int savedLimit = buffer.limit(); 357 ByteBuffer slicedPart = buffer.slice(); 358 359 buffer.position(savedLimit); 361 buffer.limit(buffer.capacity()); 362 ByteBuffer unused = buffer.slice(); 363 memoryManager.recycleMemory(unused, minSize); 364 365 return slicedPart; 366 } 367 } 368 369 370 375 static interface EventHandler { 376 377 382 public void onHandshakeFinished() throws IOException ; 383 384 385 390 public void onInAppDataReceived(LinkedList <ByteBuffer > appDataList); 391 392 393 399 public void onOutNetDataToWrite(ByteBuffer netData) throws IOException ; 400 401 402 407 public void onSSLProcessorClosed() throws IOException ; 408 } 409 } 410 | Popular Tags |