@Override protected boolean doWriteMessage(Object msg, ChannelOutboundBuffer in) throws Exception { SctpMessage packet = (SctpMessage) msg; ByteBuf data = packet.content(); int dataLen = data.readableBytes(); if (dataLen == 0) { return true; } ByteBufAllocator alloc = alloc(); boolean needsCopy = data.nioBufferCount() != 1; if (!needsCopy) { if (!data.isDirect() && alloc.isDirectBufferPooled()) { needsCopy = true; } } ByteBuffer nioData; if (!needsCopy) { nioData = data.nioBuffer(); } else { data = alloc.directBuffer(dataLen).writeBytes(data); nioData = data.nioBuffer(); } final MessageInfo mi = MessageInfo.createOutgoing(association(), null, packet.streamIdentifier()); mi.payloadProtocolID(packet.protocolIdentifier()); mi.streamNumber(packet.streamIdentifier()); mi.unordered(packet.isUnordered()); final int writtenBytes = javaChannel().send(nioData, mi); return writtenBytes > 0; }
public ByteBuf allocateBuffer(ByteBufAllocator allocator) { if (configuration.isPreferDirectBuffer()) { return allocator.ioBuffer(); } return allocator.heapBuffer(); }
/** * Adds a fragment to the block. * * @param fragment the fragment of the headers block to be added. * @param alloc allocator for new blocks if needed. * @param endOfHeaders flag indicating whether the current frame is the end of the headers. This * is used for an optimization for when the first fragment is the full block. In that case, * the buffer is used directly without copying. */ final void addFragment(ByteBuf fragment, ByteBufAllocator alloc, boolean endOfHeaders) throws Http2Exception { if (headerBlock == null) { if (fragment.readableBytes() > headersDecoder.configuration().maxHeaderSize()) { headerSizeExceeded(); } if (endOfHeaders) { // Optimization - don't bother copying, just use the buffer as-is. Need // to retain since we release when the header block is built. headerBlock = fragment.retain(); } else { headerBlock = alloc.buffer(fragment.readableBytes()); headerBlock.writeBytes(fragment); } return; } if (headersDecoder.configuration().maxHeaderSize() - fragment.readableBytes() < headerBlock.readableBytes()) { headerSizeExceeded(); } if (headerBlock.isWritable(fragment.readableBytes())) { // The buffer can hold the requested bytes, just write it directly. headerBlock.writeBytes(fragment); } else { // Allocate a new buffer that is big enough to hold the entire header block so far. ByteBuf buf = alloc.buffer(headerBlock.readableBytes() + fragment.readableBytes()); buf.writeBytes(headerBlock); buf.writeBytes(fragment); headerBlock.release(); headerBlock = buf; } }
/** * Always prefer a direct buffer when it's pooled, so that we reduce the number of memory copies * in {@link OpenSslEngine}. */ private ByteBuf allocate(ChannelHandlerContext ctx, int capacity) { ByteBufAllocator alloc = ctx.alloc(); if (wantsDirectBuffer) { return alloc.directBuffer(capacity); } else { return alloc.buffer(capacity); } }
/** * 쓰레드 덤프를 요청하는 전문을 보낸다<br> * <br> * * @param threadDumpData * @param agentId * @param channel * @author Kim Ji Hye * @since 2015. 11. 26. */ public ThreadDumpData sendThreadDumpRequest(ThreadDumpData td) { // Assembler를 사용하여 socket에 write한다. byte[] sendData = Assembler.getSendData(td, true); Channel channel = AgentClientSocketHandler.getClient(td.getAgentId()); if (channel != null) { ByteBufAllocator alloc = channel.alloc(); ByteBuf buf = alloc.buffer(sendData.length); buf.writeBytes(sendData); channel.writeAndFlush(buf); } return td; }
/** * Reads the content of the entry into a new buffer. Use {@link #readContent(ByteBufAllocator, * InputStream)} when the length of the stream is unknown. */ protected ByteBuf readContent(ByteBufAllocator alloc, InputStream in, int length) throws IOException { if (length == 0) { return Unpooled.EMPTY_BUFFER; } ByteBuf buf = null; boolean success = false; try { buf = alloc.directBuffer(length); int remaining = length; for (; ; ) { final int readBytes = buf.writeBytes(in, remaining); if (readBytes < 0) { break; } remaining -= readBytes; if (remaining <= 0) { break; } } success = true; return buf; } finally { if (!success && buf != null) { buf.release(); } } }
/** * Reads the content of the entry into a new buffer. Use {@link #readContent(ByteBufAllocator, * InputStream, int)} when the length of the stream is known. */ protected ByteBuf readContent(ByteBufAllocator alloc, InputStream in) throws IOException { ByteBuf buf = null; boolean success = false; try { buf = alloc.directBuffer(); for (; ; ) { if (buf.writeBytes(in, 8192) < 0) { break; } } success = true; if (buf.isReadable()) { return buf; } else { buf.release(); return Unpooled.EMPTY_BUFFER; } } finally { if (!success && buf != null) { buf.release(); } } }
private void run0() throws InterruptedException { ByteBufAllocator allocator = m_descriptor.getByteBufAllocator(); int initialCapacity = 4 * 1024; // 4K ByteBuf buf = allocator.buffer(initialCapacity); TransportHub hub = m_descriptor.getHub(); while (m_active.get()) { Channel channel = m_channelManager.getActiveChannel(); if (channel != null && channel.isWritable()) { do { if (hub.fill(buf)) { channel.writeAndFlush(buf); buf = allocator.buffer(initialCapacity); } else { break; } } while (channel.isWritable()); } TimeUnit.MILLISECONDS.sleep(1); // 1ms } long end = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(3); // 3s timeout while (true) { Channel channel = m_channelManager.getActiveChannel(); if (channel != null && channel.isWritable()) { do { if (hub.fill(buf)) { channel.writeAndFlush(buf); buf = allocator.buffer(initialCapacity); } else { break; } } while (channel.isWritable()); } if (System.currentTimeMillis() >= end) { throw new InterruptedException("Timeout with messages left in the queue!"); } TimeUnit.MILLISECONDS.sleep(1); // 1ms } }
private static MqttPublishMessage createPublishMessage() { MqttFixedHeader mqttFixedHeader = new MqttFixedHeader(MqttMessageType.PUBLISH, false, MqttQoS.AT_LEAST_ONCE, true, 0); MqttPublishVariableHeader mqttPublishVariableHeader = MqttPublishVariableHeader.from("/abc", 1234); ByteBuf payload = ALLOCATOR.buffer(); payload.writeBytes("whatever".getBytes(CharsetUtil.UTF_8)); return new MqttPublishMessage(mqttFixedHeader, mqttPublishVariableHeader, payload); }
@Override public ByteBuf serializeResponseAsBinary( final ResponseMessage responseMessage, final ByteBufAllocator allocator) throws SerializationException { ByteBuf encodedMessage = null; try { final Kryo kryo = kryoThreadLocal.get(); try (final OutputStream baos = new ByteArrayOutputStream()) { final Output output = new Output(baos); // request id - if present kryo.writeObjectOrNull( output, responseMessage.getRequestId() != null ? responseMessage.getRequestId() : null, UUID.class); // status output.writeShort(responseMessage.getStatus().getCode().getValue()); output.writeString(responseMessage.getStatus().getMessage()); kryo.writeClassAndObject(output, responseMessage.getStatus().getAttributes()); // result kryo.writeClassAndObject( output, serializeToString ? serializeResultToString(responseMessage) : responseMessage.getResult().getData()); kryo.writeClassAndObject(output, responseMessage.getResult().getMeta()); final long size = output.total(); if (size > Integer.MAX_VALUE) throw new SerializationException( String.format("Message size of %s exceeds allocatable space", size)); encodedMessage = allocator.buffer((int) output.total()); encodedMessage.writeBytes(output.toBytes()); } return encodedMessage; } catch (Exception ex) { if (encodedMessage != null) ReferenceCountUtil.release(encodedMessage); logger.warn( "Response [{}] could not be serialized by {}.", responseMessage.toString(), GryoMessageSerializerV1d0.class.getName()); throw new SerializationException(ex); } }
/** * Serializes the header. * * <p>A header that has metadata of small will add the length of the packet in a byte, the header * that has a metadata of big will add the length of the packet in a short */ @Override public ByteBuf serialize(ByteBufAllocator allocator) { ByteBuf buffer = allocator.buffer(1 + meta().ordinal()).writeByte(opcode()); switch (meta()) { case EMPTY: break; case SMALL: buffer.writeByte(length()); break; case BIG: buffer.writeShort(length()); break; } return buffer; }
@Override public ByteBuf serializeRequestAsBinary( final RequestMessage requestMessage, final ByteBufAllocator allocator) throws SerializationException { ByteBuf encodedMessage = null; try { final Kryo kryo = kryoThreadLocal.get(); try (final OutputStream baos = new ByteArrayOutputStream()) { final Output output = new Output(baos); final String mimeType = serializeToString ? MIME_TYPE_STRINGD : MIME_TYPE; output.writeByte(mimeType.length()); output.write(mimeType.getBytes(UTF8)); kryo.writeObject(output, requestMessage.getRequestId()); output.writeString(requestMessage.getProcessor()); output.writeString(requestMessage.getOp()); kryo.writeObject(output, requestMessage.getArgs()); final long size = output.total(); if (size > Integer.MAX_VALUE) throw new SerializationException( String.format("Message size of %s exceeds allocatable space", size)); encodedMessage = allocator.buffer((int) size); encodedMessage.writeBytes(output.toBytes()); } return encodedMessage; } catch (Exception ex) { if (encodedMessage != null) ReferenceCountUtil.release(encodedMessage); logger.warn( "Request [{}] could not be serialized by {}.", requestMessage.toString(), GryoMessageSerializerV1d0.class.getName()); throw new SerializationException(ex); } }
@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 void doWrite(ChannelOutboundBuffer in) throws Exception { int writeSpinCount = -1; GatheringByteChannel sink = connection().getSinkChannel(); for (; ; ) { // Do gathering write for a non-single buffer case. final int msgCount = in.size(); if (msgCount > 0) { // Ensure the pending writes are made of ByteBufs only. ByteBuffer[] nioBuffers = in.nioBuffers(); if (nioBuffers != null) { int nioBufferCnt = in.nioBufferCount(); long expectedWrittenBytes = in.nioBufferSize(); long writtenBytes = 0; boolean done = false; boolean setOpWrite = false; for (int i = config().getWriteSpinCount() - 1; i >= 0; i--) { final long localWrittenBytes = sink.write(nioBuffers, 0, nioBufferCnt); if (localWrittenBytes == 0) { setOpWrite = true; break; } expectedWrittenBytes -= localWrittenBytes; writtenBytes += localWrittenBytes; if (expectedWrittenBytes == 0) { done = true; break; } } if (done) { // Release all buffers for (int i = msgCount; i > 0; i--) { in.remove(); } // Finish the write loop if no new messages were flushed by in.remove(). if (in.isEmpty()) { connection().getSinkChannel().suspendWrites(); break; } } else { // Did not write all buffers completely. // Release the fully written buffers and update the indexes of the partially written // buffer. for (int i = msgCount; i > 0; i--) { final ByteBuf buf = (ByteBuf) in.current(); final int readerIndex = buf.readerIndex(); final int readableBytes = buf.writerIndex() - readerIndex; if (readableBytes < writtenBytes) { in.progress(readableBytes); in.remove(); writtenBytes -= readableBytes; } else if (readableBytes > writtenBytes) { buf.readerIndex(readerIndex + (int) writtenBytes); in.progress(writtenBytes); break; } else { // readableBytes == writtenBytes in.progress(readableBytes); in.remove(); break; } } incompleteWrite(setOpWrite); break; } continue; } } Object msg = in.current(); if (msg == null) { // Wrote all messages. connection().getSinkChannel().suspendWrites(); break; } if (msg instanceof ByteBuf) { ByteBuf buf = (ByteBuf) msg; int readableBytes = buf.readableBytes(); if (readableBytes == 0) { in.remove(); continue; } if (!buf.isDirect()) { ByteBufAllocator alloc = alloc(); if (alloc.isDirectBufferPooled()) { // Non-direct buffers are copied into JDK's own internal direct buffer on every I/O. // We can do a better job by using our pooled allocator. If the current allocator does // not // pool a direct buffer, we rely on JDK's direct buffer pool. buf = alloc.directBuffer(readableBytes).writeBytes(buf); in.current(buf); } } boolean setOpWrite = false; boolean done = false; long flushedAmount = 0; if (writeSpinCount == -1) { writeSpinCount = config().getWriteSpinCount(); } for (int i = writeSpinCount - 1; i >= 0; i--) { int localFlushedAmount = buf.readBytes(sink, buf.readableBytes()); if (localFlushedAmount == 0) { setOpWrite = true; break; } flushedAmount += localFlushedAmount; if (!buf.isReadable()) { done = true; break; } } in.progress(flushedAmount); if (done) { in.remove(); } else { incompleteWrite(setOpWrite); break; } } else if (msg instanceof FileRegion) { FileRegion region = (FileRegion) msg; boolean setOpWrite = false; boolean done = false; long flushedAmount = 0; if (writeSpinCount == -1) { writeSpinCount = config().getWriteSpinCount(); } for (int i = writeSpinCount - 1; i >= 0; i--) { long localFlushedAmount = region.transferTo(sink, region.transfered()); if (localFlushedAmount == 0) { setOpWrite = true; break; } flushedAmount += localFlushedAmount; if (region.transfered() >= region.count()) { done = true; break; } } in.progress(flushedAmount); if (done) { in.remove(); } else { incompleteWrite(setOpWrite); break; } } else { throw new UnsupportedOperationException( "unsupported message type: " + StringUtil.simpleClassName(msg)); } } }
@Override protected boolean doWriteMessage(Object msg, ChannelOutboundBuffer in) throws Exception { final Object m; final SocketAddress remoteAddress; ByteBuf data; if (msg instanceof AddressedEnvelope) { @SuppressWarnings("unchecked") AddressedEnvelope<Object, SocketAddress> envelope = (AddressedEnvelope<Object, SocketAddress>) msg; remoteAddress = envelope.recipient(); m = envelope.content(); } else { m = msg; remoteAddress = null; } if (m instanceof ByteBufHolder) { data = ((ByteBufHolder) m).content(); } else if (m instanceof ByteBuf) { data = (ByteBuf) m; } else { throw new UnsupportedOperationException( "unsupported message type: " + StringUtil.simpleClassName(msg)); } int dataLen = data.readableBytes(); if (dataLen == 0) { return true; } ByteBufAllocator alloc = alloc(); boolean needsCopy = data.nioBufferCount() != 1; if (!needsCopy) { if (!data.isDirect() && alloc.isDirectBufferPooled()) { needsCopy = true; } } ByteBuffer nioData; if (!needsCopy) { nioData = data.nioBuffer(); } else { data = alloc.directBuffer(dataLen).writeBytes(data); nioData = data.nioBuffer(); } final int writtenBytes; if (remoteAddress != null) { writtenBytes = javaChannel().send(nioData, remoteAddress); } else { writtenBytes = javaChannel().write(nioData); } boolean done = writtenBytes > 0; if (needsCopy) { // This means we have allocated a new buffer and need to store it back so we not need to // allocate it again // later if (remoteAddress == null) { // remoteAddress is null which means we can handle it as ByteBuf directly in.current(data); } else { if (!done) { // store it back with all the needed informations in.current(new DefaultAddressedEnvelope<ByteBuf, SocketAddress>(data, remoteAddress)); } else { // Just store back the new create buffer so it is cleaned up once in.remove() is called. in.current(data); } } } return done; }
@Override public ByteBuf allocate(ByteBufAllocator alloc) { return alloc.ioBuffer(nextReceiveBufferSize); }
public GameFrameBuilder(ByteBufAllocator alloc, int opcode, Type type) { this.alloc = alloc; this.buffer = alloc.buffer(); this.opcode = opcode; this.type = type; }