org.glassfish.grizzly.nio.transport.TCPNIOUtils Maven / Gradle / Ivy
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2012-2016 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package org.glassfish.grizzly.nio.transport;
import java.io.EOFException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.glassfish.grizzly.Buffer;
import org.glassfish.grizzly.memory.BufferArray;
import org.glassfish.grizzly.memory.Buffers;
import org.glassfish.grizzly.memory.ByteBufferArray;
import org.glassfish.grizzly.memory.CompositeBuffer;
import org.glassfish.grizzly.memory.MemoryManager;
import org.glassfish.grizzly.nio.DirectByteBufferRecord;
import org.glassfish.grizzly.utils.Exceptions;
/**
* TCP NIO Transport utils
*
* @author Alexey Stashok
*/
public class TCPNIOUtils {
static final Logger LOGGER = TCPNIOTransport.LOGGER;
public static int writeCompositeBuffer(final TCPNIOConnection connection,
final CompositeBuffer buffer) throws IOException {
final int bufferSize = calcWriteBufferSize(connection, buffer.remaining());
final int oldPos = buffer.position();
final int oldLim = buffer.limit();
buffer.limit(oldPos + bufferSize);
final SocketChannel socketChannel = (SocketChannel) connection.getChannel();
int written = 0;
final BufferArray bufferArray = buffer.toBufferArray();
final DirectByteBufferRecord ioRecord = DirectByteBufferRecord.get();
try {
fill(bufferArray, bufferSize, ioRecord);
ioRecord.finishBufferSlice();
final int arraySize = ioRecord.getArraySize();
written = arraySize != 1
? flushByteBuffers(socketChannel, ioRecord.getArray(), 0, arraySize)
: flushByteBuffer(socketChannel, ioRecord.getArray()[0]);
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.log(Level.FINE, "TCPNIOConnection ({0}) (composite) write {1} bytes", new Object[]{
connection, written
});
}
} finally {
ioRecord.release();
bufferArray.restore();
bufferArray.recycle();
}
Buffers.setPositionLimit(buffer, oldPos + written, oldLim);
return written;
}
public static int writeSimpleBuffer(final TCPNIOConnection connection,
final Buffer buffer) throws IOException {
final SocketChannel socketChannel = (SocketChannel) connection.getChannel();
final int oldPos = buffer.position();
final int oldLim = buffer.limit();
final int written;
if (buffer.isDirect()) {
final ByteBuffer directByteBuffer = buffer.toByteBuffer();
final int pos = directByteBuffer.position();
try {
written = flushByteBuffer(socketChannel, directByteBuffer);
} finally {
directByteBuffer.position(pos);
}
} else {
final int bufferSize = calcWriteBufferSize(connection, buffer.remaining());
buffer.limit(oldPos + bufferSize);
final DirectByteBufferRecord ioRecord =
DirectByteBufferRecord.get();
final ByteBuffer directByteBuffer = ioRecord.allocate(bufferSize);
fill(buffer, bufferSize, directByteBuffer);
try {
written = flushByteBuffer(socketChannel, directByteBuffer);
} finally {
ioRecord.release();
}
}
Buffers.setPositionLimit(buffer, oldPos + written, oldLim);
if(LOGGER.isLoggable(Level.FINE))
LOGGER.log(Level.FINE, "TCPNIOConnection ({0}) (plain) write {1} bytes", new Object[] {
connection, written
});
return written;
}
public static int flushByteBuffer(final SocketChannel channel,
final ByteBuffer byteBuffer) throws IOException {
return channel.write(byteBuffer);
}
public static int flushByteBuffers(final SocketChannel channel,
final ByteBuffer byteBuffer[], final int firstBufferOffest,
final int numberOfBuffers) throws IOException {
return (int) channel.write(byteBuffer, firstBufferOffest, numberOfBuffers);
}
private static void fill(Buffer src, int size, ByteBuffer dstByteBuffer)
{
dstByteBuffer.limit(size);
int oldPos = src.position();
src.get(dstByteBuffer);
dstByteBuffer.position(0);
src.position(oldPos);
}
static void fill(final BufferArray bufferArray,
final int totalBufferSize, final DirectByteBufferRecord ioRecord) {
final Buffer buffers[] = bufferArray.getArray();
final int size = bufferArray.size();
int totalRemaining = totalBufferSize;
for (int i = 0; i < size; i++) {
final Buffer buffer = buffers[i];
assert !buffer.isComposite();
final int bufferSize = buffer.remaining();
if (bufferSize == 0) {
continue;
}
if (buffer.isDirect()) {
ioRecord.finishBufferSlice();
ioRecord.putToArray(buffer.toByteBuffer());
} else {
ByteBuffer currentDirectBufferSlice = ioRecord.getDirectBufferSlice();
if (currentDirectBufferSlice == null) {
final ByteBuffer directByteBuffer = ioRecord.getDirectBuffer();
if (directByteBuffer == null) {
ioRecord.allocate(totalRemaining); // allocate buffer big enough to put the entire message (not just the chunk we're writing)
}
currentDirectBufferSlice = ioRecord.sliceBuffer();
}
final int oldLim = currentDirectBufferSlice.limit();
currentDirectBufferSlice.limit(currentDirectBufferSlice.position() + bufferSize);
buffer.get(currentDirectBufferSlice);
currentDirectBufferSlice.limit(oldLim);
}
totalRemaining -= bufferSize;
}
}
private static int calcWriteBufferSize(final TCPNIOConnection connection,
final int bufferSize) {
return Math.min(TCPNIOTransport.MAX_SEND_BUFFER_SIZE,
Math.min(bufferSize, (connection.getWriteBufferSize() * 3) / 2));
}
public static Buffer allocateAndReadBuffer(final TCPNIOConnection connection)
throws IOException {
final MemoryManager memoryManager = connection.getMemoryManager();
int read;
Throwable error = null;
Buffer buffer = null;
try {
final int receiveBufferSize =
Math.min(TCPNIOTransport.MAX_RECEIVE_BUFFER_SIZE,
connection.getReadBufferSize());
if (!memoryManager.willAllocateDirect(receiveBufferSize)) {
final DirectByteBufferRecord ioRecord =
DirectByteBufferRecord.get();
final ByteBuffer directByteBuffer =
ioRecord.allocate(receiveBufferSize);
try {
read = readSimpleByteBuffer(connection, directByteBuffer);
if (read > 0) {
directByteBuffer.flip();
buffer = memoryManager.allocate(read);
buffer.put(directByteBuffer);
}
} finally {
ioRecord.release();
}
} else {
buffer = memoryManager.allocateAtLeast(receiveBufferSize);
read = readBuffer(connection, buffer);
}
} catch (Throwable e) {
error = e;
read = -1;
}
if (read > 0) {
buffer.position(read);
buffer.allowBufferDispose(true);
} else {
if (buffer != null) {
buffer.dispose();
}
if (read < 0) {
//noinspection ThrowableResultOfMethodCallIgnored
throw error != null
? Exceptions.makeIOException(error)
: new EOFException();
}
buffer = Buffers.EMPTY_BUFFER;
}
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.log(Level.FINE, "TCPNIOConnection ({0}) (allocated) read {1} bytes", new Object[]{
connection, read
});
}
return buffer;
}
public static int readBuffer(final TCPNIOConnection connection,
final Buffer buffer) throws IOException {
return buffer.isComposite()
? readCompositeBuffer(connection, (CompositeBuffer) buffer)
: readSimpleBuffer(connection, buffer);
}
public static int readCompositeBuffer(final TCPNIOConnection connection,
final CompositeBuffer buffer) throws IOException {
final SocketChannel socketChannel = (SocketChannel) connection.getChannel();
final int oldPos = buffer.position();
final ByteBufferArray array = buffer.toByteBufferArray();
final ByteBuffer byteBuffers[] = array.getArray();
final int size = array.size();
final int read = (int) socketChannel.read(byteBuffers, 0, size);
array.restore();
array.recycle();
if (read > 0) {
buffer.position(oldPos + read);
}
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.log(Level.FINE, "TCPNIOConnection ({0}) (nonallocated, composite) read {1} bytes", new Object[]{
connection, read
});
}
return read;
}
public static int readSimpleBuffer(final TCPNIOConnection connection,
final Buffer buffer) throws IOException {
final SocketChannel socketChannel = (SocketChannel) connection.getChannel();
final int oldPos = buffer.position();
final ByteBuffer byteBuffer = buffer.toByteBuffer();
final int bbOldPos = byteBuffer.position();
final int read = socketChannel.read(byteBuffer);
if (read > 0) {
byteBuffer.position(bbOldPos);
buffer.position(oldPos + read);
}
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.log(Level.FINE, "TCPNIOConnection ({0}) (nonallocated, simple) read {1} bytes", new Object[]{
connection, read
});
}
return read;
}
private static int readSimpleByteBuffer(final TCPNIOConnection tcpConnection,
final ByteBuffer byteBuffer) throws IOException {
final SocketChannel socketChannel = (SocketChannel) tcpConnection.getChannel();
return socketChannel.read(byteBuffer);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy