@Override protected int doReadMessages(List<Object> buf) throws Exception { DatagramChannel ch = javaChannel(); DatagramChannelConfig config = config(); RecvByteBufAllocator.Handle allocHandle = unsafe().recvBufAllocHandle(); ByteBuf data = allocHandle.allocate(config.getAllocator()); allocHandle.attemptedBytesRead(data.writableBytes()); boolean free = true; try { ByteBuffer nioData = data.internalNioBuffer(data.writerIndex(), data.writableBytes()); int pos = nioData.position(); InetSocketAddress remoteAddress = (InetSocketAddress) ch.receive(nioData); if (remoteAddress == null) { return 0; } allocHandle.lastBytesRead(nioData.position() - pos); buf.add( new DatagramPacket( data.writerIndex(data.writerIndex() + allocHandle.lastBytesRead()), localAddress(), remoteAddress)); free = false; return 1; } catch (Throwable cause) { PlatformDependent.throwException(cause); return -1; } finally { if (free) { data.release(); } } }
private SSLEngineResult unwrap( SSLEngine engine, ByteBuf in, int readerIndex, int len, ByteBuf out) throws SSLException { int nioBufferCount = in.nioBufferCount(); int writerIndex = out.writerIndex(); final SSLEngineResult result; if (engine instanceof OpenSslEngine && nioBufferCount > 1) { /** * If {@link OpenSslEngine} is in use, we can use a special {@link * OpenSslEngine#unwrap(ByteBuffer[], ByteBuffer[])} method that accepts multiple {@link * ByteBuffer}s without additional memory copies. */ OpenSslEngine opensslEngine = (OpenSslEngine) engine; try { singleBuffer[0] = toByteBuffer(out, writerIndex, out.writableBytes()); result = opensslEngine.unwrap(in.nioBuffers(readerIndex, len), singleBuffer); out.writerIndex(writerIndex + result.bytesProduced()); } finally { singleBuffer[0] = null; } } else { result = engine.unwrap( toByteBuffer(in, readerIndex, len), toByteBuffer(out, writerIndex, out.writableBytes())); } out.writerIndex(writerIndex + result.bytesProduced()); return result; }
@Override public ByteBuf translateFrame(ByteBuf readBuffer) throws LimitExedeedException, InvalidDataException { while (readBuffer.isReadable()) { switch (status) { case STATUS_H: h = readBuffer.readByte(); status = STATUS_L; break; case STATUS_L: l = readBuffer.readByte(); final int blen = Protocol.order == ByteOrder.BIG_ENDIAN ? (0x0000ff00 & (h << 8)) | (0x000000ff & l) : (0x0000ff00 & (l << 8)) | (0x000000ff & h); if (context != null) { if (blen <= 0 || blen > maxFrameSize) { throw new LimitExedeedException("帧长度非法:" + h + "/" + l + ":" + blen); } } incompleteframe = PooledByteBufAllocator.DEFAULT.buffer(blen + 16 + 2); incompleteframe = incompleteframe.order(Protocol.order); incompleteframe.writeShort(blen); status = STATUS_C; break; case STATUS_C: int len = incompleteframe.writableBytes() - 16; len = len < readBuffer.readableBytes() ? len : readBuffer.readableBytes(); // incompleteframe.writeBytes(readBuffer, len); if (readBuffer.hasMemoryAddress()) { PlatformDependent.copyMemory( readBuffer.memoryAddress() + readBuffer.readerIndex(), incompleteframe.memoryAddress() + incompleteframe.writerIndex(), len); } else if (readBuffer.hasArray()) { PlatformDependent.copyMemory( readBuffer.array(), readBuffer.arrayOffset() + readBuffer.readerIndex(), incompleteframe.memoryAddress() + incompleteframe.writerIndex(), len); } incompleteframe.writerIndex(incompleteframe.writerIndex() + len); readBuffer.readerIndex(readBuffer.readerIndex() + len); if ((incompleteframe.writableBytes() - 16) <= 0) { status = STATUS_H; return incompleteframe; } break; } } return null; }
@Override protected int doReadMessages(List<Object> buf) throws Exception { SctpChannel ch = javaChannel(); RecvByteBufAllocator.Handle allocHandle = unsafe().recvBufAllocHandle(); ByteBuf buffer = allocHandle.allocate(config().getAllocator()); boolean free = true; try { ByteBuffer data = buffer.internalNioBuffer(buffer.writerIndex(), buffer.writableBytes()); int pos = data.position(); MessageInfo messageInfo = ch.receive(data, null, notificationHandler); if (messageInfo == null) { return 0; } buf.add( new SctpMessage( messageInfo, buffer.writerIndex(buffer.writerIndex() + data.position() - pos))); free = false; return 1; } catch (Throwable cause) { PlatformDependent.throwException(cause); return -1; } finally { int bytesRead = buffer.readableBytes(); allocHandle.record(bytesRead); if (free) { buffer.release(); } } }
@Override protected int doReadMessages(MessageBuf<Object> buf) throws Exception { DatagramChannel ch = javaChannel(); ByteBuf buffer = alloc().directBuffer(config().getReceivePacketSize()); boolean free = true; try { ByteBuffer data = buffer.nioBuffer(buffer.writerIndex(), buffer.writableBytes()); InetSocketAddress remoteAddress = (InetSocketAddress) ch.receive(data); if (remoteAddress == null) { return 0; } buf.add( new DatagramPacket( buffer.writerIndex(buffer.writerIndex() + data.remaining()), remoteAddress)); free = false; return 1; } catch (Throwable cause) { if (cause instanceof Error) { throw (Error) cause; } if (cause instanceof RuntimeException) { throw (RuntimeException) cause; } if (cause instanceof Exception) { throw (Exception) cause; } throw new ChannelException(cause); } finally { if (free) { buffer.free(); } } }
private boolean handleCompressedFrame(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { if (!in.isReadable(FRAME_COMPRESS_HEADER_LENGTH)) { return false; } int compressedPayloadLength = in.readInt(); if (!in.isReadable(compressedPayloadLength)) { return false; } // decompress payload Inflater inflater = new Inflater(); if (in.hasArray()) { inflater.setInput(in.array(), in.arrayOffset() + in.readerIndex(), compressedPayloadLength); in.skipBytes(compressedPayloadLength); } else { byte[] array = new byte[compressedPayloadLength]; in.readBytes(array); inflater.setInput(array); } while (!inflater.finished()) { ByteBuf decompressed = ctx.alloc().heapBuffer(1024, 1024); byte[] outArray = decompressed.array(); int count = inflater.inflate(outArray, decompressed.arrayOffset(), decompressed.writableBytes()); decompressed.writerIndex(count); // put data in the pipeline out.add(decompressed); } return true; }
private void testBuffer(ByteBuf buf, boolean isDirect) { assertEquals(11, buf.capacity()); assertEquals(isDirect, buf.isDirect()); assertEquals(0, buf.readableBytes()); assertEquals(11, buf.writableBytes()); }
private void writeBuffer(byte[] data) { int newSize = 0; int oldSize = buffer.capacity(); int length = data.length; if (buffer.writableBytes() <= length) { if (length > oldSize) { newSize = length * 2; } else { newSize = 2 * oldSize; } buffer.capacity(newSize); } buffer.writeBytes(data); }
private static SSLEngineResult wrap(SSLEngine engine, ByteBuf in, ByteBuf out) throws SSLException { ByteBuffer in0 = in.nioBuffer(); for (; ; ) { ByteBuffer out0 = out.nioBuffer(out.writerIndex(), out.writableBytes()); SSLEngineResult result = engine.wrap(in0, out0); in.skipBytes(result.bytesConsumed()); out.writerIndex(out.writerIndex() + result.bytesProduced()); if (result.getStatus() == Status.BUFFER_OVERFLOW) { out.ensureWritableBytes(engine.getSession().getPacketBufferSize()); } else { return result; } } }
/** Read bytes into the given {@link ByteBuf} and return the amount. */ private int doReadBytes(ByteBuf byteBuf) throws Exception { int writerIndex = byteBuf.writerIndex(); int localReadAmount; if (byteBuf.hasMemoryAddress()) { localReadAmount = Native.readAddress(fd, byteBuf.memoryAddress(), writerIndex, byteBuf.capacity()); } else { ByteBuffer buf = byteBuf.internalNioBuffer(writerIndex, byteBuf.writableBytes()); localReadAmount = Native.read(fd, buf, buf.position(), buf.limit()); } if (localReadAmount > 0) { byteBuf.writerIndex(writerIndex + localReadAmount); } return localReadAmount; }
private static SSLEngineResult unwrap(SSLEngine engine, ByteBuf in, ByteBuf out) throws SSLException { ByteBuffer in0 = in.nioBuffer(); for (; ; ) { ByteBuffer out0 = out.nioBuffer(out.writerIndex(), out.writableBytes()); SSLEngineResult result = engine.unwrap(in0, out0); in.skipBytes(result.bytesConsumed()); out.writerIndex(out.writerIndex() + result.bytesProduced()); switch (result.getStatus()) { case BUFFER_OVERFLOW: out.ensureWritableBytes(engine.getSession().getApplicationBufferSize()); break; default: return result; } } }
@Override public void handleEvent(ConduitStreamSourceChannel channel) { final ChannelConfig config = config(); final ChannelPipeline pipeline = pipeline(); final ByteBufAllocator allocator = config.getAllocator(); final int maxMessagesPerRead = config.getMaxMessagesPerRead(); RecvByteBufAllocator.Handle allocHandle = this.allocHandle; if (allocHandle == null) { this.allocHandle = allocHandle = config.getRecvByteBufAllocator().newHandle(); } if (!config.isAutoRead()) { removeReadOp(channel); } ByteBuf byteBuf = null; int messages = 0; boolean close = false; try { do { byteBuf = allocHandle.allocate(allocator); int localReadAmount = byteBuf.writeBytes(channel, byteBuf.writableBytes()); if (localReadAmount <= 0) { // not was read release the buffer byteBuf.release(); close = localReadAmount < 0; break; } pipeline.fireChannelRead(byteBuf); byteBuf = null; allocHandle.record(localReadAmount); } while (++messages < maxMessagesPerRead); pipeline.fireChannelReadComplete(); if (close) { closeOnRead(); close = false; } } catch (Throwable t) { handleReadException(pipeline, byteBuf, t, close); } }
private static SSLEngineResult unwrap(SSLEngine engine, ByteBuffer in, ByteBuf out) throws SSLException { int overflows = 0; for (; ; ) { ByteBuffer out0 = out.nioBuffer(out.writerIndex(), out.writableBytes()); SSLEngineResult result = engine.unwrap(in, out0); out.writerIndex(out.writerIndex() + result.bytesProduced()); switch (result.getStatus()) { case BUFFER_OVERFLOW: int max = engine.getSession().getApplicationBufferSize(); switch (overflows++) { case 0: out.ensureWritable(Math.min(max, in.remaining())); break; default: out.ensureWritable(max); } break; default: return result; } } }
@Override protected void encode(ChannelHandlerContext ctx, Object msg, List<Object> out) throws Exception { ByteBuf buf = null; if (msg instanceof HttpMessage) { if (state != ST_INIT) { throw new IllegalStateException( "unexpected message type: " + StringUtil.simpleClassName(msg)); } @SuppressWarnings({"unchecked", "CastConflictsWithInstanceof"}) H m = (H) msg; buf = ctx.alloc().buffer(); // Encode the message. encodeInitialLine(buf, m); HttpHeaders.encode(m.headers(), buf); buf.writeBytes(CRLF); state = HttpHeaders.isTransferEncodingChunked(m) ? ST_CONTENT_CHUNK : ST_CONTENT_NON_CHUNK; } if (msg instanceof HttpContent || msg instanceof ByteBuf || msg instanceof FileRegion) { if (state == ST_INIT) { throw new IllegalStateException( "unexpected message type: " + StringUtil.simpleClassName(msg)); } int contentLength = contentLength(msg); if (state == ST_CONTENT_NON_CHUNK) { if (contentLength > 0) { if (buf != null && buf.writableBytes() >= contentLength && msg instanceof HttpContent) { // merge into other buffer for performance reasons buf.writeBytes(((HttpContent) msg).content()); out.add(buf); } else { if (buf != null) { out.add(buf); } out.add(encodeAndRetain(msg)); } } else { if (buf != null) { out.add(buf); } else { // Need to produce some output otherwise an // IllegalStateException will be thrown out.add(EMPTY_BUFFER); } } if (msg instanceof LastHttpContent) { state = ST_INIT; } } else if (state == ST_CONTENT_CHUNK) { if (buf != null) { out.add(buf); } encodeChunkedContent(ctx, msg, contentLength, out); } else { throw new Error(); } } else { if (buf != null) { out.add(buf); } } }
@Override void epollInReady() { final ChannelConfig config = config(); final ChannelPipeline pipeline = pipeline(); final ByteBufAllocator allocator = config.getAllocator(); RecvByteBufAllocator.Handle allocHandle = this.allocHandle; if (allocHandle == null) { this.allocHandle = allocHandle = config.getRecvByteBufAllocator().newHandle(); } ByteBuf byteBuf = null; boolean close = false; try { int byteBufCapacity = allocHandle.guess(); int totalReadAmount = 0; for (; ; ) { // we use a direct buffer here as the native implementations only be able // to handle direct buffers. byteBuf = allocator.directBuffer(byteBufCapacity); int writable = byteBuf.writableBytes(); int localReadAmount = doReadBytes(byteBuf); if (localReadAmount <= 0) { // not was read release the buffer byteBuf.release(); close = localReadAmount < 0; break; } readPending = false; pipeline.fireChannelRead(byteBuf); byteBuf = null; if (totalReadAmount >= Integer.MAX_VALUE - localReadAmount) { allocHandle.record(totalReadAmount); // Avoid overflow. totalReadAmount = localReadAmount; } else { totalReadAmount += localReadAmount; } if (localReadAmount < writable) { // Read less than what the buffer can hold, // which might mean we drained the recv buffer completely. break; } } pipeline.fireChannelReadComplete(); allocHandle.record(totalReadAmount); if (close) { closeOnRead(pipeline); close = false; } } catch (Throwable t) { boolean closed = handleReadException(pipeline, byteBuf, t, close); if (!closed) { // trigger a read again as there may be something left to read and because of epoll ET we // will not get notified again until we read everything from the socket eventLoop() .execute( new Runnable() { @Override public void run() { epollInReady(); } }); } } finally { // Check if there is a readPending which was not processed yet. // This could be for two reasons: // * The user called Channel.read() or ChannelHandlerContext.read() in channelRead(...) // method // * The user called Channel.read() or ChannelHandlerContext.read() in // channelReadComplete(...) method // // See https://github.com/netty/netty/issues/2254 if (!config.isAutoRead() && !readPending) { clearEpollIn0(); } } }
private SSLEngineResult wrap(ByteBufAllocator alloc, SSLEngine engine, ByteBuf in, ByteBuf out) throws SSLException { ByteBuf newDirectIn = null; try { int readerIndex = in.readerIndex(); int readableBytes = in.readableBytes(); // We will call SslEngine.wrap(ByteBuffer[], ByteBuffer) to allow efficient handling of // CompositeByteBuf without force an extra memory copy when CompositeByteBuffer.nioBuffer() is // called. final ByteBuffer[] in0; if (in.isDirect() || !wantsDirectBuffer) { // As CompositeByteBuf.nioBufferCount() can be expensive (as it needs to check all composed // ByteBuf // to calculate the count) we will just assume a CompositeByteBuf contains more then 1 // ByteBuf. // The worst that can happen is that we allocate an extra ByteBuffer[] in // CompositeByteBuf.nioBuffers() // which is better then walking the composed ByteBuf in most cases. if (!(in instanceof CompositeByteBuf) && in.nioBufferCount() == 1) { in0 = singleBuffer; // We know its only backed by 1 ByteBuffer so use internalNioBuffer to keep object // allocation // to a minimum. in0[0] = in.internalNioBuffer(readerIndex, readableBytes); } else { in0 = in.nioBuffers(); } } else { // We could even go further here and check if its a CompositeByteBuf and if so try to // decompose it and // only replace the ByteBuffer that are not direct. At the moment we just will replace the // whole // CompositeByteBuf to keep the complexity to a minimum newDirectIn = alloc.directBuffer(readableBytes); newDirectIn.writeBytes(in, readerIndex, readableBytes); in0 = singleBuffer; in0[0] = newDirectIn.internalNioBuffer(0, readableBytes); } for (; ; ) { ByteBuffer out0 = out.nioBuffer(out.writerIndex(), out.writableBytes()); SSLEngineResult result = engine.wrap(in0, out0); in.skipBytes(result.bytesConsumed()); out.writerIndex(out.writerIndex() + result.bytesProduced()); switch (result.getStatus()) { case BUFFER_OVERFLOW: out.ensureWritable(maxPacketBufferSize); break; default: return result; } } } finally { // Null out to allow GC of ByteBuffer singleBuffer[0] = null; if (newDirectIn != null) { newDirectIn.release(); } } }
@Override protected int doReadBytes(ByteBuf byteBuf) throws Exception { // 从channel中读出数据到buffer return byteBuf.writeBytes(javaChannel(), byteBuf.writableBytes()); }
@Override public int writableBytes() { return buf.writableBytes(); }