| /* |
| * 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 -= FLAGS_OFFSET; |
| |
| 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 + FLAGS_OFFSET; |
| 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(); |
| } |
| } |