/* * Copyright (c) 2011, 2012, 2015 Eike Stepper (Berlin, Germany) and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Teerawat Chaiyakijpichet (No Magic Asia Ltd.) - initial API and implementation * Caspar De Groot (No Magic Asia Ltd.) - initial API and implementation */ package org.eclipse.net4j.internal.tcp.ssl; import org.eclipse.net4j.buffer.BufferState; import org.eclipse.net4j.buffer.IBuffer; import org.eclipse.net4j.buffer.IBufferProvider; import org.eclipse.net4j.internal.tcp.bundle.OM; import org.eclipse.net4j.util.StringUtil; import org.eclipse.net4j.util.om.trace.ContextTracer; import org.eclipse.internal.net4j.buffer.Buffer; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import java.nio.channels.SocketChannel; /** * All source code same as org.eclipse.internal.net4j.buffer.Buffer except adding SSLEngineManager to constructor and * overriding startGetting and write method in order to attach the SSL functional. * * @author Teerawat Chaiyakijpichet (No Magic Asia Ltd.) * @author Caspar De Groot (No Magic Asia Ltd.) * @since 4.0 */ public class SSLBuffer extends Buffer { private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG_SSLBUFFER, SSLBuffer.class); private SSLEngineManager sslEngineManager; public SSLBuffer(IBufferProvider provider, short capacity, SSLEngineManager sslEngineManager) { super(provider, capacity); this.sslEngineManager = sslEngineManager; } @Override public ByteBuffer startGetting(SocketChannel socketChannel) throws IOException { BufferState state = getState(); if (state != BufferState.INITIAL && state != BufferState.READING_HEADER && state != BufferState.READING_BODY) { throw new IllegalStateException(toString()); } int readSize = 0; if (sslEngineManager.getAppRecvBuf().position() > 0) { readSize = sslEngineManager.getAppRecvBuf().position(); } else { readSize = sslEngineManager.read(socketChannel); } if (readSize > 0) { ByteBuffer buf = sslEngineManager.getAppRecvBuf(); buf.flip(); int limit = buf.limit(); ByteBuffer byteBuffer = getByteBuffer(); int capacity = byteBuffer.capacity(); limit = limit > capacity ? capacity : limit; byteBuffer.put(buf.array(), 0, limit); buf.position(limit); buf.compact(); byteBuffer.flip(); setChannelID(byteBuffer.getShort()); short payloadSize = byteBuffer.getShort(); if (payloadSize < 0) { setEOS(true); payloadSize = (short)-payloadSize; } payloadSize -= MAKE_PAYLOAD_SIZE_NON_ZERO; byteBuffer.position(IBuffer.HEADER_SIZE); setState(BufferState.READING_HEADER); byteBuffer.compact(); byteBuffer.limit(payloadSize); setState(BufferState.READING_BODY); byteBuffer.flip(); setState(BufferState.GETTING); return byteBuffer; } else if (readSize < 0) { throw new ClosedChannelException(); } return null; } /** * @return <code>true</code> if the buffer has been completely written, <code>false</code> otherwise. */ @Override public boolean write(SocketChannel socketChannel) throws IOException { try { if (sslEngineManager.getPacketSendBuf().position() > 0) { sslEngineManager.handleWrite(socketChannel); if (sslEngineManager.getPacketSendBuf().position() > 0) { clear(); return false; } clear(); return true; } BufferState state = getState(); if (state != BufferState.PUTTING && state != BufferState.WRITING) { throw new IllegalStateException(toString()); } ByteBuffer byteBuffer = getByteBuffer(); if (state == BufferState.PUTTING) { if (getChannelID() == NO_CHANNEL) { throw new IllegalStateException("channelID == NO_CHANNEL"); //$NON-NLS-1$ } int payloadSize = byteBuffer.position() - IBuffer.HEADER_SIZE + MAKE_PAYLOAD_SIZE_NON_ZERO; if (isEOS()) { payloadSize = -payloadSize; } if (TRACER.isEnabled()) { TRACER.trace("Writing " + (Math.abs(payloadSize) - 1) + " bytes" //$NON-NLS-1$ //$NON-NLS-2$ + (isEOS() ? " (EOS)" : "") + StringUtil.NL + formatContent(false)); //$NON-NLS-1$ //$NON-NLS-2$ } byteBuffer.flip(); byteBuffer.putShort(getChannelID()); byteBuffer.putShort((short)payloadSize); byteBuffer.position(0); setState(BufferState.WRITING); } sslEngineManager.getAppSendBuf().put(byteBuffer); sslEngineManager.write(socketChannel); if (sslEngineManager.getPacketSendBuf().position() > 0) { clear(); return false; } clear(); return true; } catch (IOException ex) { handleError(ex); throw ex; } catch (RuntimeException ex) { handleError(ex); throw ex; } catch (Error ex) { handleError(ex); throw ex; } } @Override public void dispose() { sslEngineManager = null; super.dispose(); } }