public void write(final byte[] data, final int offset, final int len) throws IOException { logger.debug("{} Writing {} bytes of data", this, len); if (!connected) { connect(); } int iterations = len / MAX_WRITE_SIZE; if (len % MAX_WRITE_SIZE > 0) { iterations++; } for (int i = 0; i < iterations; i++) { streamOutManager.clear(); final int itrOffset = offset + i * MAX_WRITE_SIZE; final int itrLen = Math.min(len - itrOffset, MAX_WRITE_SIZE); final ByteBuffer byteBuffer = ByteBuffer.wrap(data, itrOffset, itrLen); final BufferStateManager buffMan = new BufferStateManager(byteBuffer, Direction.READ); final Status status = encryptAndWriteFully(buffMan); switch (status) { case BUFFER_OVERFLOW: streamOutManager.ensureSize(engine.getSession().getPacketBufferSize()); appDataManager.ensureSize(engine.getSession().getApplicationBufferSize()); continue; case OK: continue; case CLOSED: throw new IOException("Channel is closed"); case BUFFER_UNDERFLOW: throw new AssertionError("Got Buffer Underflow but should not have..."); } } }
appDataManager.clear(); final ByteBuffer streamInBuffer = streamInManager.prepareForRead(1); SSLEngineResult unwrapResponse = null; final ByteBuffer appDataBuffer = appDataManager.prepareForWrite(engine.getSession().getApplicationBufferSize()); unwrapResponse = engine.unwrap(streamInBuffer, appDataBuffer); logger.trace("{} When reading data, (handshake={}) Unwrap response: {}", this, handshaking, unwrapResponse); final ByteBuffer writableInBuffer = streamInManager.prepareForWrite(engine.getSession().getPacketBufferSize()); final int bytesRead = readData(writableInBuffer); if (bytesRead < 0) { throw new IOException("Failed to decrypt data"); streamInManager.compact(); return copied;
public boolean isDataAvailable() throws IOException { final ByteBuffer appDataBuffer = appDataManager.prepareForRead(1); final ByteBuffer streamDataBuffer = streamInManager.prepareForRead(1); if (appDataBuffer.remaining() > 0 || streamDataBuffer.remaining() > 0) { return true; } final ByteBuffer writableBuffer = streamInManager.prepareForWrite(engine.getSession().getPacketBufferSize()); final int bytesRead = channel.read(writableBuffer); return (bytesRead > 0); }
private Status encryptAndWriteFully(final BufferStateManager src) throws IOException { SSLEngineResult result = null; final ByteBuffer buff = src.prepareForRead(0); final ByteBuffer outBuff = streamOutManager.prepareForWrite(engine.getSession().getApplicationBufferSize()); logger.trace("{} Encrypting {} bytes", this, buff.remaining()); while (buff.remaining() > 0) { result = engine.wrap(buff, outBuff); if (result.getStatus() == Status.OK) { final ByteBuffer readableOutBuff = streamOutManager.prepareForRead(0); writeFully(readableOutBuff); streamOutManager.clear(); } else { return result.getStatus(); } } return result.getStatus(); }
final ByteBuffer writableInBuffer = streamInManager.prepareForWrite(engine.getSession().getPacketBufferSize()); int readCount = 0; try { logger.trace("{} Read {} bytes", this, readCount); final ByteBuffer streamInBuffer = streamInManager.prepareForRead(1); final ByteBuffer appDataBuffer = appDataManager.prepareForWrite(engine.getSession().getApplicationBufferSize()); try { SSLEngineResult unwrapResponse = engine.unwrap(streamInBuffer, appDataBuffer); streamInManager.compact(); return false;
public ByteBuffer prepareForRead(final int requiredSize) { ensureSize(requiredSize); if (direction == Direction.WRITE) { direction = Direction.READ; buffer.flip(); } return buffer; }
public SSLSocketChannel(final SSLContext sslContext, final String hostname, final int port, final InetAddress localAddress, final boolean client) throws IOException { this.socketAddress = new InetSocketAddress(hostname, port); this.channel = SocketChannel.open(); if (localAddress != null) { final SocketAddress localSocketAddress = new InetSocketAddress(localAddress, 0); this.channel.bind(localSocketAddress); } this.hostname = hostname; this.port = port; this.engine = sslContext.createSSLEngine(); this.engine.setUseClientMode(client); engine.setNeedClientAuth(true); streamInManager = new BufferStateManager(ByteBuffer.allocate(engine.getSession().getPacketBufferSize())); streamOutManager = new BufferStateManager(ByteBuffer.allocate(engine.getSession().getPacketBufferSize())); appDataManager = new BufferStateManager(ByteBuffer.allocate(engine.getSession().getApplicationBufferSize())); }
public int available() throws IOException { ByteBuffer appDataBuffer = appDataManager.prepareForRead(1); ByteBuffer streamDataBuffer = streamInManager.prepareForRead(1); final int buffered = appDataBuffer.remaining() + streamDataBuffer.remaining(); if (buffered > 0) { return buffered; } final boolean wasAbleToRead = isDataAvailable(); if (!wasAbleToRead) { return 0; } appDataBuffer = appDataManager.prepareForRead(1); streamDataBuffer = streamInManager.prepareForRead(1); return appDataBuffer.remaining() + streamDataBuffer.remaining(); }
private Status encryptAndWriteFully(final BufferStateManager src) throws IOException { SSLEngineResult result = null; final ByteBuffer buff = src.prepareForRead(0); final ByteBuffer outBuff = streamOutManager.prepareForWrite(engine.getSession().getApplicationBufferSize()); logger.trace("{} Encrypting {} bytes", this, buff.remaining()); while (buff.remaining() > 0) { result = engine.wrap(buff, outBuff); if (result.getStatus() == Status.OK) { final ByteBuffer readableOutBuff = streamOutManager.prepareForRead(0); writeFully(readableOutBuff); streamOutManager.clear(); } else { return result.getStatus(); } } return result.getStatus(); }
final ByteBuffer writableInBuffer = streamInManager.prepareForWrite(engine.getSession().getPacketBufferSize()); int readCount = 0; try { logger.trace("{} Read {} bytes", this, readCount); final ByteBuffer streamInBuffer = streamInManager.prepareForRead(1); final ByteBuffer appDataBuffer = appDataManager.prepareForWrite(engine.getSession().getApplicationBufferSize()); try { SSLEngineResult unwrapResponse = engine.unwrap(streamInBuffer, appDataBuffer); streamInManager.compact(); return false;
final ByteBuffer outboundBuffer = streamOutManager.prepareForWrite(engine.getSession().getApplicationBufferSize()); final SSLEngineResult handshakeResult = engine.wrap(appDataOut, outboundBuffer); final ByteBuffer readableStreamOut = streamOutManager.prepareForRead(1); writeFully(readableStreamOut); } finally {
public ByteBuffer prepareForWrite(final int requiredSize) { ensureSize(requiredSize); if (direction == Direction.READ) { direction = Direction.WRITE; buffer.position(buffer.limit()); } buffer.limit(buffer.capacity()); return buffer; }
public SSLSocketChannel(final SSLEngine sslEngine, final SocketChannel socketChannel) throws IOException { if (!socketChannel.isConnected()) { throw new IllegalArgumentException("Cannot pass an un-connected SocketChannel"); } this.channel = socketChannel; this.socketAddress = socketChannel.getRemoteAddress(); final Socket socket = socketChannel.socket(); this.hostname = socket.getInetAddress().getHostName(); this.port = socket.getPort(); // don't set useClientMode or needClientAuth, use the engine as is and let the caller configure it this.engine = sslEngine; streamInManager = new BufferStateManager(ByteBuffer.allocate(engine.getSession().getPacketBufferSize())); streamOutManager = new BufferStateManager(ByteBuffer.allocate(engine.getSession().getPacketBufferSize())); appDataManager = new BufferStateManager(ByteBuffer.allocate(engine.getSession().getApplicationBufferSize())); }
private int copyFromAppDataBuffer(final byte[] buffer, final int offset, final int len) { // If any data already exists in the application data buffer, copy it to the buffer. final ByteBuffer appDataBuffer = appDataManager.prepareForRead(1); final int appDataRemaining = appDataBuffer.remaining(); if (appDataRemaining > 0) { final int bytesToCopy = Math.min(len, appDataBuffer.remaining()); appDataBuffer.get(buffer, offset, bytesToCopy); final int bytesCopied = appDataRemaining - appDataBuffer.remaining(); logger.trace("{} Copied {} ({}) bytes from unencrypted application buffer to user space", this, bytesToCopy, bytesCopied); return bytesCopied; } return 0; }
final ByteBuffer appDataOut = ByteBuffer.wrap(emptyMessage); final ByteBuffer outboundBuffer = streamOutManager.prepareForWrite(engine.getSession().getApplicationBufferSize()); streamOutManager.prepareForWrite(engine.getSession().getApplicationBufferSize()); continue; final ByteBuffer readableStreamOut = streamOutManager.prepareForRead(1); final int bytesToSend = readableStreamOut.remaining(); writeFully(readableStreamOut); logger.trace("{} Sent {} bytes of wrapped data for handshake", this, bytesToSend); streamOutManager.clear(); final ByteBuffer readableDataIn = streamInManager.prepareForRead(0); final ByteBuffer appData = appDataManager.prepareForWrite(engine.getSession().getApplicationBufferSize()); final ByteBuffer writableDataIn = streamInManager.prepareForWrite(engine.getSession().getPacketBufferSize()); final int bytesRead = readData(writableDataIn); if (bytesRead > 0) { throw new IOException("Channel was closed by peer during handshake"); } else { streamInManager.compact(); appDataManager.clear();
public void write(final byte[] data, final int offset, final int len) throws IOException { logger.debug("{} Writing {} bytes of data", this, len); if (!connected) { connect(); } int iterations = len / MAX_WRITE_SIZE; if (len % MAX_WRITE_SIZE > 0) { iterations++; } for (int i = 0; i < iterations; i++) { streamOutManager.clear(); final int itrOffset = offset + i * MAX_WRITE_SIZE; final int itrLen = Math.min(len - itrOffset, MAX_WRITE_SIZE); final ByteBuffer byteBuffer = ByteBuffer.wrap(data, itrOffset, itrLen); final BufferStateManager buffMan = new BufferStateManager(byteBuffer, Direction.READ); final Status status = encryptAndWriteFully(buffMan); switch (status) { case BUFFER_OVERFLOW: streamOutManager.ensureSize(engine.getSession().getPacketBufferSize()); appDataManager.ensureSize(engine.getSession().getApplicationBufferSize()); continue; case OK: continue; case CLOSED: throw new IOException("Channel is closed"); case BUFFER_UNDERFLOW: throw new AssertionError("Got Buffer Underflow but should not have..."); } } }
public boolean isDataAvailable() throws IOException { final ByteBuffer appDataBuffer = appDataManager.prepareForRead(1); final ByteBuffer streamDataBuffer = streamInManager.prepareForRead(1); if (appDataBuffer.remaining() > 0 || streamDataBuffer.remaining() > 0) { return true; } final ByteBuffer writableBuffer = streamInManager.prepareForWrite(engine.getSession().getPacketBufferSize()); final int bytesRead = channel.read(writableBuffer); return (bytesRead > 0); }
public ByteBuffer prepareForRead(final int requiredSize) { ensureSize(requiredSize); if (direction == Direction.WRITE) { direction = Direction.READ; buffer.flip(); } return buffer; }