
com.generallycloud.baseio.component.NioSocketChannel Maven / Gradle / Ivy
/*
* Copyright 2015-2017 GenerallyCloud.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.generallycloud.baseio.component;
import static com.generallycloud.baseio.Develop.printException;
import static com.generallycloud.baseio.common.ThrowableUtil.unknownStackTrace;
import java.io.Closeable;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketOption;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLEngineResult;
import javax.net.ssl.SSLEngineResult.HandshakeStatus;
import javax.net.ssl.SSLEngineResult.Status;
import javax.net.ssl.SSLException;
import com.generallycloud.baseio.buffer.ByteBuf;
import com.generallycloud.baseio.buffer.ByteBufAllocator;
import com.generallycloud.baseio.buffer.EmptyByteBuf;
import com.generallycloud.baseio.collection.Attributes;
import com.generallycloud.baseio.collection.AttributesImpl;
import com.generallycloud.baseio.common.Assert;
import com.generallycloud.baseio.common.CloseUtil;
import com.generallycloud.baseio.common.ReleaseUtil;
import com.generallycloud.baseio.common.ThrowableUtil;
import com.generallycloud.baseio.component.ChannelContext.HeartBeatLogger;
import com.generallycloud.baseio.concurrent.ExecutorEventLoop;
import com.generallycloud.baseio.log.Logger;
import com.generallycloud.baseio.log.LoggerFactory;
import com.generallycloud.baseio.protocol.Frame;
import com.generallycloud.baseio.protocol.ProtocolCodec;
public final class NioSocketChannel extends AttributesImpl
implements Runnable, Attributes, Closeable {
private static final ClosedChannelException CLOSED_WHEN_FLUSH = CLOSED_WHEN_FLUSH();
private static final InetSocketAddress ERROR_SOCKET_ADDRESS = new InetSocketAddress(0);
private static final Logger logger = newLogger();
private static final SSLException NOT_TLS = NOT_TLS();
private static final int SSL_PACKET_LIMIT = 1024 * 64;
private static final SSLException SSL_PACKET_OVER_LIMIT = SSL_PACKET_OVER_LIMIT();
private static final SSLException SSL_UNWRAP_OVER_LIMIT = SSL_UNWRAP_OVER_LIMIT();
private final SocketChannel channel;
private final Integer channelId;
private ProtocolCodec codec;
private final ChannelContext context;
private final long creationTime = System.currentTimeMillis();
private final ByteBuf[] currentWriteBufs;
private int currentWriteBufsLen;
private final String desc;
private final boolean enableSsl;
private final NioEventLoop eventLoop;
private final ExecutorEventLoop executorEventLoop;
private boolean inEventBuffer;
private IoEventHandle ioEventHandle;
private long lastAccess;
private final String localAddr;
private final int localPort;
private final int maxWriteBacklog;
private volatile boolean opened = true;
private ByteBuf plainRemainBuf;
private final String remoteAddr;
private final String remoteAddrPort;
private final int remotePort;
private final SelectionKey selKey;
private final SSLEngine sslEngine;
private boolean sslHandshakeFinished;
private ByteBuf sslRemainBuf;
private byte sslWrapExt;
private final Queue writeBufs;
NioSocketChannel(NioEventLoop el, SelectionKey sk, ChannelContext ctx, int chId) {
NioEventLoopGroup g = el.getGroup();
this.context = ctx;
this.selKey = sk;
this.eventLoop = el;
this.channelId = chId;
this.enableSsl = ctx.isEnableSsl();
this.codec = ctx.getProtocolCodec();
this.maxWriteBacklog = ctx.getMaxWriteBacklog();
this.currentWriteBufs = new ByteBuf[g.getWriteBuffers()];
this.executorEventLoop = ctx.getExecutorEventLoopGroup().getNext();
this.channel = (SocketChannel) sk.channel();
this.lastAccess = creationTime + g.getIdleTime();
this.writeBufs = new LinkedBlockingQueue<>();
//请勿使用remote.getRemoteHost(),可能出现阻塞
InetSocketAddress remote = getRemoteSocketAddress0();
InetSocketAddress local = getLocalSocketAddress0();
String idhex = Integer.toHexString(chId);
this.remoteAddr = remote.getAddress().getHostAddress();
this.remotePort = remote.getPort();
this.remoteAddrPort = remoteAddr + ":" + remotePort;
this.localAddr = local.getAddress().getHostAddress();
this.localPort = local.getPort();
this.desc = "[id(0x" + idhex + ")R/" + remoteAddrPort + "; L:" + getLocalPort() + "]";
if (ctx.isEnableSsl()) {
this.sslEngine = ctx.getSslContext().newEngine(remoteAddr, remotePort);
} else {
this.sslEngine = null;
}
}
private void accept(ByteBuf src) throws IOException {
final ProtocolCodec codec = this.codec;
final IoEventHandle eventHandle = this.ioEventHandle;
final HeartBeatLogger heartBeatLogger = context.getHeartBeatLogger();
final boolean enableWorkEventLoop = context.isEnableWorkEventLoop();
for (;;) {
Frame frame = codec.decode(this, src);
if (frame == null) {
plainRemainBuf = sliceRemain(src);
break;
}
if (frame.isTyped()) {
if (frame.isPing()) {
heartBeatLogger.logPing(this);
Frame f = codec.pong(this, frame);
if (f != null) {
flush(f);
}
} else if (frame.isPong()) {
heartBeatLogger.logPong(this);
}
} else {
if (enableWorkEventLoop) {
accept(eventHandle, frame);
} else {
try {
eventHandle.accept(this, frame);
} catch (Exception e) {
eventHandle.exceptionCaught(this, frame, e);
}
}
}
if (!src.hasRemaining()) {
break;
}
}
}
private void accept(final IoEventHandle eventHandle, final Frame frame) {
getExecutorEventLoop().execute(new Runnable() {
@Override
public void run() {
try {
eventHandle.accept(NioSocketChannel.this, frame);
} catch (Exception e) {
eventHandle.exceptionCaught(NioSocketChannel.this, frame, e);
}
}
});
}
public ByteBufAllocator alloc() {
return eventLoop.alloc();
}
@Override
public void close() {
if (inEventLoop()) {
safeClose();
} else {
if (isClosed()) {
return;
}
execute(new CloseEvent(this));
}
}
private void closeSsl() {
if (enableSsl) {
if (!channel.isOpen()) {
return;
}
sslEngine.closeOutbound();
if (context.getSslContext().isClient()) {
try {
writeBufs.offer(wrap(EmptyByteBuf.get()));
write(selKey.interestOps());
} catch (Exception e) {}
}
try {
sslEngine.closeInbound();
} catch (Exception e) {}
}
}
public ByteBuf encode(Frame frame) throws IOException {
return codec.encode(this, frame);
}
private void exceptionCaught(Frame frame, Exception ex) {
try {
getIoEventHandle().exceptionCaught(this, frame, ex);
} catch (Throwable e) {
printException(logger, e);
printException(logger, ex);
}
}
private void execute(Runnable event) {
eventLoop.execute(event);
}
private void finishHandshake() {
sslHandshakeFinished = true;
if (context.getSslContext().isClient()) {
ChannelConnector connector = (ChannelConnector) context;
connector.finishConnect(this, null);
}
fireOpend();
}
private void fireClosed() {
final NioSocketChannel ch = this;
eventLoop.removeChannel(ch.channelId);
for (ChannelEventListener l : context.getChannelEventListeners()) {
try {
l.channelClosed(ch);
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
}
protected void fireOpend() {
final NioSocketChannel ch = this;
for (ChannelEventListener l : context.getChannelEventListeners()) {
try {
l.channelOpened(ch);
} catch (Exception e) {
logger.error(e.getMessage(), e);
CloseUtil.close(ch);
return;
}
}
if (ioEventHandle == null) {
ioEventHandle = context.getIoEventHandle();
}
}
public void flush(ByteBuf buf) {
Assert.notNull(buf, "null buf");
if (enableSsl) {
ByteBuf old = buf;
try {
buf = wrap(old);
} catch (Exception e) {
printException(logger, e);
} finally {
old.release();
}
}
if (inEventLoop()) {
if (isClosed()) {
buf.release();
return;
}
writeBufs.offer(buf);
if (!inEventBuffer) {
inEventBuffer = true;
eventLoop.flush(this);
}
} else {
Queue writeBufs = this.writeBufs;
if (isClosed()) {
buf.release();
return;
}
writeBufs.offer(buf);
if (isClosed()) {
ReleaseUtil.release(writeBufs.poll());
return;
}
//FIXME 确认这里这么判断是否有问题
if (writeBufs.size() != 1) {
return;
}
eventLoop.flushAndWakeup(this);
}
}
public void flush(Frame frame) {
Assert.notNull(frame, "null frame");
if (isClosed()) {
exceptionCaught(frame, CLOSED_WHEN_FLUSH);
return;
}
ByteBuf buf = null;
try {
buf = codec.encode(this, frame);
} catch (Exception e) {
ReleaseUtil.release(buf);
exceptionCaught(frame, e);
return;
}
flush(buf);
}
//FIXME ..使用该方法貌似会性能下降?查找原因
public void flush(List bufs) {
if (bufs != null && !bufs.isEmpty()) {
if (inEventLoop()) {
if (isClosed()) {
ReleaseUtil.release(bufs);
return;
}
final int bufsSize = bufs.size();
final Queue writeBufs = this.writeBufs;
if (writeBufs.isEmpty()) {
final ByteBuf[] currentWriteBufs = this.currentWriteBufs;
final int maxLen = currentWriteBufs.length;
int currentWriteBufsLen = this.currentWriteBufsLen;
if (currentWriteBufsLen == 0) {
if (bufsSize > maxLen) {
for (int i = 0; i < maxLen; i++) {
currentWriteBufs[i] = bufs.get(i);
}
for (int i = maxLen; i < bufsSize; i++) {
writeBufs.offer(bufs.get(i));
}
this.currentWriteBufsLen = maxLen;
} else {
for (int i = 0; i < bufsSize; i++) {
currentWriteBufs[i] = bufs.get(i);
}
this.currentWriteBufsLen = bufsSize;
}
} else {
final int currentRemain = maxLen - currentWriteBufsLen;
if (bufsSize > currentRemain) {
for (int i = 0; i < currentRemain; i++) {
currentWriteBufs[i + currentWriteBufsLen] = bufs.get(i);
}
for (int i = currentRemain; i < bufsSize; i++) {
writeBufs.offer(bufs.get(i));
}
this.currentWriteBufsLen = maxLen;
} else {
for (int i = 0; i < bufsSize; i++) {
currentWriteBufs[i + currentWriteBufsLen] = bufs.get(i);
}
this.currentWriteBufsLen += bufsSize;
}
}
} else {
for (ByteBuf buf : bufs) {
writeBufs.offer(buf);
}
}
if (!inEventBuffer) {
inEventBuffer = true;
eventLoop.flush(this);
}
} else {
Queue writeBufs = this.writeBufs;
if (isClosed()) {
ReleaseUtil.release(bufs);
return;
}
for (ByteBuf buf : bufs) {
writeBufs.offer(buf);
}
if (isClosed()) {
releaseWriteBufQueue();
return;
}
//FIXME 确认这里这么判断是否有问题
if (writeBufs.size() != bufs.size()) {
return;
}
eventLoop.flushAndWakeup(this);
}
}
}
public Integer getChannelId() {
return channelId;
}
public Charset getCharset() {
return context.getCharset();
}
public ProtocolCodec getCodec() {
return codec;
}
public String getCodecId() {
return codec.getProtocolId();
}
public ChannelContext getContext() {
return context;
}
public long getCreationTime() {
return creationTime;
}
public NioEventLoop getEventLoop() {
return eventLoop;
}
public ExecutorEventLoop getExecutorEventLoop() {
return executorEventLoop;
}
public IoEventHandle getIoEventHandle() {
return ioEventHandle;
}
public long getLastAccessTime() {
return lastAccess;
}
public String getLocalAddr() {
return localAddr;
}
public int getLocalPort() {
return localPort;
}
private InetSocketAddress getLocalSocketAddress0() {
try {
return (InetSocketAddress) channel.getLocalAddress();
} catch (IOException e) {
return ERROR_SOCKET_ADDRESS;
}
}
public T getOption(SocketOption name) throws IOException {
return channel.getOption(name);
}
public String getRemoteAddr() {
return remoteAddr;
}
public String getRemoteAddrPort() {
return remoteAddrPort;
}
public int getRemotePort() {
return remotePort;
}
private InetSocketAddress getRemoteSocketAddress0() {
try {
return (InetSocketAddress) channel.getRemoteAddress();
} catch (Exception e) {}
return ERROR_SOCKET_ADDRESS;
}
public SSLEngine getSSLEngine() {
return sslEngine;
}
public int getWriteBacklog() {
//忽略current write[]
return writeBufs.size();
}
//FIXME not correct ,fix this
private int guessWrapOut(int src, int ext) {
if (SslContext.OPENSSL_AVAILABLE) {
return ((src + SslContext.SSL_PACKET_BUFFER_SIZE - 1)
/ SslContext.SSL_PACKET_BUFFER_SIZE + 1) * ext + src;
} else {
return ((src + SslContext.SSL_PACKET_BUFFER_SIZE - 1)
/ SslContext.SSL_PACKET_BUFFER_SIZE)
* (ext + SslContext.SSL_PACKET_BUFFER_SIZE);
}
}
@Override
public int hashCode() {
return remoteAddrPort.hashCode();
}
public boolean inEventLoop() {
return eventLoop.inEventLoop();
}
private void interestRead(SelectionKey key, int interestOps) {
if (SelectionKey.OP_READ != interestOps) {
key.interestOps(SelectionKey.OP_READ);
}
}
private void interestWrite(SelectionKey key, int interestOps) {
if ((SelectionKey.OP_READ | SelectionKey.OP_WRITE) != interestOps) {
key.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE);
}
}
public boolean isBlocking() {
return channel.isBlocking();
}
public boolean isClosed() {
return !opened;
}
public boolean isCodec(String codecId) {
return codec.getProtocolId().equals(codecId);
}
public boolean isEnableSsl() {
return enableSsl;
}
/**
record type (1 byte)
/
/ version (1 byte major, 1 byte minor)
/ /
/ / length (2 bytes)
/ / /
+----+----+----+----+----+
| | | | | |
| | | | | | TLS Record header
+----+----+----+----+----+
Record Type Values dec hex
-------------------------------------
CHANGE_CIPHER_SPEC 20 0x14
ALERT 21 0x15
HANDSHAKE 22 0x16
APPLICATION_DATA 23 0x17
Version Values dec hex
-------------------------------------
SSL 3.0 3,0 0x0300
TLS 1.0 3,1 0x0301
TLS 1.1 3,2 0x0302
TLS 1.2 3,3 0x0303
ref:http://blog.fourthbit.com/2014/12/23/traffic-analysis-of-an-ssl-slash-tls-session/
*/
private boolean isEnoughSslUnwrap(ByteBuf src) throws SSLException {
if (src.remaining() < 5) {
return false;
}
int pos = src.position();
// TLS - Check ContentType
int type = src.getUnsignedByte(pos);
if (type < 20 || type > 23) {
throw NOT_TLS;
}
// TLS - Check ProtocolVersion
int majorVersion = src.getUnsignedByte(pos + 1);
int minorVersion = src.getUnsignedByte(pos + 2);
int packetLength = src.getUnsignedShort(pos + 3);
if (majorVersion != 3 || minorVersion < 1) {
// NOT TLS (i.e. SSLv2,3 or bad data)
throw NOT_TLS;
}
int len = packetLength + 5;
if (src.remaining() < len) {
return false;
}
if (len > SSL_PACKET_LIMIT) {
throw SSL_PACKET_OVER_LIMIT;
}
src.markL();
src.limit(pos + len);
return true;
}
public boolean isOpened() {
return opened;
}
protected void read(ByteBuf src) throws IOException {
lastAccess = System.currentTimeMillis();
src.clear();
if (enableSsl) {
readSslRemainingBuf(src);
int length = channel.read(src.nioBuffer());
if (length < 1) {
if (length == -1) {
CloseUtil.close(this);
return;
}
if (src.position() > 0) {
src.flip();
sslRemainBuf = sliceRemain(src);
}
return;
}
src.reverse();
src.flip();
for (;;) {
if (isEnoughSslUnwrap(src)) {
ByteBuf res = unwrap(src);
if (res != null) {
accept(res);
}
src.resetL();
if (!src.hasRemaining()) {
return;
}
} else {
if (src.hasRemaining()) {
sslRemainBuf = sliceRemain(src);
}
return;
}
}
} else {
readPlainRemainingBuf(src);
int length = channel.read(src.nioBuffer());
if (length < 1) {
if (length == -1) {
CloseUtil.close(this);
return;
}
if (src.position() > 0) {
src.flip();
plainRemainBuf = sliceRemain(src);
}
return;
}
src.reverse();
src.flip();
accept(src);
}
}
private void readPlainRemainingBuf(ByteBuf dst) {
ByteBuf remainingBuf = this.plainRemainBuf;
if (remainingBuf == null) {
return;
}
dst.read(remainingBuf);
remainingBuf.release();
this.plainRemainBuf = null;
}
private void readSslRemainingBuf(ByteBuf dst) {
ByteBuf remainingBuf = this.sslRemainBuf;
if (remainingBuf == null) {
return;
}
dst.read(remainingBuf);
remainingBuf.release();
this.sslRemainBuf = null;
}
public void release(Frame frame) {
codec.release(eventLoop, frame);
}
private void releaseWriteBufArray() {
final ByteBuf[] cwbs = this.currentWriteBufs;
final int maxLen = cwbs.length;
// 这里有可能是因为异常关闭,currentWriteFrameLen不准确
// 对所有不为空的frame release
for (int i = 0; i < maxLen; i++) {
ByteBuf buf = cwbs[i];
if (buf == null) {
break;
}
buf.release();
cwbs[i] = null;
}
}
private void releaseWriteBufQueue() {
Queue wfs = this.writeBufs;
if (!wfs.isEmpty()) {
ByteBuf buf = wfs.poll();
for (; buf != null;) {
ReleaseUtil.release(buf);
buf = wfs.poll();
}
}
}
@Override
public void run() {
if (isOpened()) {
inEventBuffer = false;
try {
write(selKey.interestOps());
} catch (Exception e) {
close();
}
}
}
private void runDelegatedTasks(SSLEngine engine) {
for (;;) {
Runnable task = engine.getDelegatedTask();
if (task == null) {
break;
}
task.run();
}
}
private void safeClose() {
if (isOpened()) {
opened = false;
closeSsl();
releaseWriteBufQueue();
releaseWriteBufArray();
ReleaseUtil.release(sslRemainBuf);
ReleaseUtil.release(plainRemainBuf);
CloseUtil.close(channel);
selKey.attach(null);
selKey.cancel();
fireClosed();
stopContext();
clearAttributes();
}
}
public void setCodec(ProtocolCodec codec) {
this.codec = codec;
}
public void setIoEventHandle(IoEventHandle ioEventHandle) {
this.ioEventHandle = ioEventHandle;
}
public void setOption(SocketOption name, T value) throws IOException {
channel.setOption(name, value);
}
private ByteBuf sliceRemain(ByteBuf src) {
int remain = src.remaining();
ByteBuf remaining = alloc().allocate(remain);
remaining.read(src);
return remaining.flip();
}
private void stopContext() {
if (context instanceof ChannelConnector) {
CloseUtil.close(((ChannelConnector) context));
}
}
//FIXME 部分buf不需要swap
private ByteBuf swap(ByteBufAllocator allocator, ByteBuf buf) {
ByteBuf out = allocator.allocate(buf.limit());
out.read(buf);
return out.flip();
}
private void synchByteBuf(SSLEngineResult result, ByteBuf src, ByteBuf dst) {
//FIXME 同步。。。。。
src.reverse();
dst.reverse();
// int bytesConsumed = result.bytesConsumed();
// int bytesProduced = result.bytesProduced();
//
// if (bytesConsumed > 0) {
// src.skipBytes(bytesConsumed);
// }
//
// if (bytesProduced > 0) {
// dst.skipBytes(bytesProduced);
// }
}
@Override
public String toString() {
return desc;
}
private ByteBuf unwrap(ByteBuf src) throws IOException {
SSLEngine sslEngine = getSSLEngine();
ByteBuf dst = FastThreadLocal.get().getSslUnwrapBuf();
if (sslHandshakeFinished) {
dst.clear();
readPlainRemainingBuf(dst);
SSLEngineResult result = sslEngine.unwrap(src.nioBuffer(), dst.nioBuffer());
if (result.getStatus() == Status.BUFFER_OVERFLOW) {
//why throw an exception here instead of handle it?
//the getSslUnwrapBuf will return an thread local buffer for unwrap,
//the buffer's size defined by Constants.SSL_UNWRAP_BUFFER_SIZE_KEY in System property
//or default value 256KB(1024 * 256), although the buffer will not occupy so much memory because
//one EventLoop only have one buffer,but before do unwrap, every channel maybe cached a large
//buffer under SSL_UNWRAP_BUFFER_SIZE,I do not think it is a good way to cached much memory in
//channel, it is not friendly for load much channels in one system, if you get exception here,
//you may need find a way to limit you frame size,or cache your incomplete frame's data to
//file system or others way.
throw SSL_UNWRAP_OVER_LIMIT;
}
synchByteBuf(result, src, dst);
return dst.flip();
} else {
for (;;) {
dst.clear();
SSLEngineResult result = sslEngine.unwrap(src.nioBuffer(), dst.nioBuffer());
HandshakeStatus handshakeStatus = result.getHandshakeStatus();
synchByteBuf(result, src, dst);
if (handshakeStatus == HandshakeStatus.NEED_WRAP) {
flush(EmptyByteBuf.get());
return null;
} else if (handshakeStatus == HandshakeStatus.NEED_TASK) {
runDelegatedTasks(sslEngine);
continue;
} else if (handshakeStatus == HandshakeStatus.FINISHED) {
finishHandshake();
return null;
} else if (handshakeStatus == HandshakeStatus.NEED_UNWRAP) {
if (src.hasRemaining()) {
continue;
}
return null;
}
}
}
}
private ByteBuf wrap(ByteBuf src) throws IOException {
SSLEngine engine = getSSLEngine();
ByteBufAllocator alloc = alloc();
ByteBuf out = null;
try {
if (sslHandshakeFinished) {
byte sslWrapExt = this.sslWrapExt;
if (sslWrapExt == 0) {
out = alloc.allocate(guessWrapOut(src.limit(), 0xff + 1));
} else {
out = alloc.allocate(guessWrapOut(src.limit(), sslWrapExt & 0xff));
}
final int SSL_PACKET_BUFFER_SIZE = SslContext.SSL_PACKET_BUFFER_SIZE;
for (;;) {
SSLEngineResult result = engine.wrap(src.nioBuffer(), out.nioBuffer());
Status status = result.getStatus();
synchByteBuf(result, src, out);
if (status == Status.CLOSED) {
return out.flip();
} else if (status == Status.BUFFER_OVERFLOW) {
ByteBuf old = out;
try {
int len = out.capacity() + SSL_PACKET_BUFFER_SIZE;
out = alloc.allocate(len);
out.read(old.flip());
} finally {
old.release();
}
continue;
} else {
if (src.hasRemaining()) {
continue;
}
if (sslWrapExt == 0) {
int srcLen = src.limit();
int outLen = out.position();
int y = ((srcLen + 1) / SSL_PACKET_BUFFER_SIZE) + 1;
int u = ((outLen - srcLen) / y) * 2;
this.sslWrapExt = (byte) u;
}
return out.flip();
}
}
} else {
ByteBuf dst = FastThreadLocal.get().getSslWrapBuf();
for (;;) {
dst.clear();
SSLEngineResult result = engine.wrap(src.nioBuffer(), dst.nioBuffer());
Status status = result.getStatus();
HandshakeStatus handshakeStatus = result.getHandshakeStatus();
synchByteBuf(result, src, dst);
if (status == Status.CLOSED) {
return swap(alloc, dst.flip());
}
if (handshakeStatus == HandshakeStatus.NEED_UNWRAP) {
if (out != null) {
out.read(dst.flip());
return out.flip();
}
return swap(alloc, dst.flip());
} else if (handshakeStatus == HandshakeStatus.NEED_WRAP) {
if (out == null) {
out = alloc.allocate(256);
}
out.read(dst.flip());
continue;
} else if (handshakeStatus == HandshakeStatus.FINISHED) {
finishHandshake();
if (out != null) {
out.read(dst.flip());
return out.flip();
}
return swap(alloc, dst.flip());
} else if (handshakeStatus == HandshakeStatus.NEED_TASK) {
runDelegatedTasks(engine);
continue;
}
}
}
} catch (Throwable e) {
ReleaseUtil.release(out);
if (e instanceof IOException) {
throw (IOException) e;
}
throw new IOException(e);
}
}
protected boolean write(final int interestOps) throws IOException {
final NioEventLoop eventLoop = this.eventLoop;
final Queue writeBufs = this.writeBufs;
final SelectionKey selectionKey = this.selKey;
final ByteBuf[] cwBufs = this.currentWriteBufs;
final ByteBuffer[] writeBuffers = eventLoop.getWriteBuffers();
final int maxLen = cwBufs.length;
for (;;) {
int cwLen = this.currentWriteBufsLen;
for (; cwLen < maxLen;) {
ByteBuf buf = writeBufs.poll();
if (buf == null) {
break;
}
cwBufs[cwLen++] = buf;
}
if (cwLen == 0) {
interestRead(selectionKey, interestOps);
return true;
}
for (int i = 0; i < cwLen; i++) {
ByteBuf buf = cwBufs[i];
writeBuffers[i] = buf.nioBuffer();
}
if (cwLen == 1) {
ByteBuffer nioBuf = writeBuffers[0];
channel.write(nioBuf);
if (nioBuf.hasRemaining()) {
this.currentWriteBufsLen = 1;
cwBufs[0].reverse();
interestWrite(selectionKey, interestOps);
return false;
} else {
ByteBuf buf = cwBufs[0];
cwBufs[0] = null;
buf.release();
this.currentWriteBufsLen = 0;
if (writeBufs.isEmpty()) {
interestRead(selectionKey, interestOps);
return true;
}
continue;
}
} else {
channel.write(writeBuffers, 0, cwLen);
for (int i = 0; i < cwLen; i++) {
ByteBuf buf = cwBufs[i];
if (writeBuffers[i].hasRemaining()) {
buf.reverse();
int remain = cwLen - i;
System.arraycopy(cwBufs, i, cwBufs, 0, remain);
fillNull(cwBufs, remain, cwLen);
fillNull(writeBuffers, i, cwLen);
this.currentWriteBufsLen = remain;
interestWrite(selectionKey, interestOps);
if (writeBufs.size() > maxWriteBacklog) {
close();
}
return false;
} else {
writeBuffers[i] = null;
buf.release();
}
}
fillNull(cwBufs, 0, cwLen);
this.currentWriteBufsLen = 0;
if (writeBufs.isEmpty()) {
interestRead(selectionKey, interestOps);
return true;
}
}
}
}
class CloseEvent implements Runnable, Closeable {
final NioSocketChannel ch;
public CloseEvent(NioSocketChannel ch) {
this.ch = ch;
}
@Override
public void close() throws IOException {
ch.safeClose();
}
@Override
public void run() {
ch.safeClose();
}
}
private static ClosedChannelException CLOSED_WHEN_FLUSH() {
return ThrowableUtil.unknownStackTrace(new ClosedChannelException(), NioSocketChannel.class,
"flush(...)");
}
private static void fillNull(Object[] a, int fromIndex, int toIndex) {
for (int i = fromIndex; i < toIndex; i++)
a[i] = null;
}
private static Logger newLogger() {
return LoggerFactory.getLogger(NioSocketChannel.class);
}
private static SSLException NOT_TLS() {
return ThrowableUtil.unknownStackTrace(new SSLException("NOT TLS"), NioSocketChannel.class,
"isEnoughSslUnwrap()");
}
private static SSLException SSL_PACKET_OVER_LIMIT() {
return ThrowableUtil.unknownStackTrace(
new SSLException("over limit (" + SSL_PACKET_LIMIT + ")"), NioSocketChannel.class,
"isEnoughSslUnwrap()");
}
private static SSLException SSL_UNWRAP_OVER_LIMIT() {
return unknownStackTrace(new SSLException("over limit (SSL_UNWRAP_BUFFER_SIZE)"),
NioSocketChannel.class, "unwrap()");
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy