blob: 4acffce8e3cabc8d95dd7b683c50ca696b4f16cc [file] [log] [blame]
/*
* 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();
}
}