Writing a read-only direct ByteBuffer to channel fails with native transport
See original GitHub issueExpected behavior
I can take a direct ByteBuffer where isReadOnly()
is true, such as the return value of asReadOnlyBuffer()
or a MappedBuffer with MapMode.READ_ONLY
, pass it to Unpooled.wrappedBuffer(ByteBuffer)
, and write it to the channel.
Actual behavior
Works with NIO transport. When using kqueue or epoll native transport, writing to the channel fails due to UnsupportedOperationException produced by ReadOnlyByteBufferBuf.memoryAddress()
.
Minimal yet complete reproducer code
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(new KQueueEventLoopGroup());
bootstrap.channel(KQueueSocketChannel.class);
bootstrap.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast("HttpResponseDecoder", new HttpResponseDecoder());
ch.pipeline().addLast("HttpRequestEncoder", new HttpRequestEncoder());
}
});
final Path path = Paths.get("src/test/resources/upload.txt");
final FileChannel fileChannel = FileChannel.open(path, StandardOpenOption.READ);
final ByteBuffer dst = ByteBuffer.allocateDirect((int) fileChannel.size());
fileChannel.read(dst, 0);
dst.flip();
bootstrap.connect("httpbin.org", 80).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
final Channel channel = future.channel();
DefaultHttpHeaders headers = new DefaultHttpHeaders();
headers.add("Content-Length", fileChannel.size());
DefaultHttpRequest req = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, "/post", headers);
channel.write(req);
channel.write(Unpooled.wrappedBuffer(dst.asReadOnlyBuffer()));
channel.writeAndFlush(DefaultLastHttpContent.EMPTY_LAST_CONTENT).addListener(new GenericFutureListener<Future<? super Void>>() {
@Override
public void operationComplete(Future<? super Void> future) throws Exception {
if (!future.isSuccess()) {
future.cause().printStackTrace();
}
}
});
}
});
The above code prints this stack trace when run:
io.netty.channel.socket.ChannelOutputShutdownException: Channel output shutdown
at io.netty.channel.AbstractChannel$AbstractUnsafe.shutdownOutput(AbstractChannel.java:641)
at io.netty.channel.AbstractChannel$AbstractUnsafe.flush0(AbstractChannel.java:948)
at io.netty.channel.AbstractChannel$AbstractUnsafe.flush(AbstractChannel.java:901)
at io.netty.channel.DefaultChannelPipeline$HeadContext.flush(DefaultChannelPipeline.java:1374)
at io.netty.channel.AbstractChannelHandlerContext.invokeFlush0(AbstractChannelHandlerContext.java:776)
at io.netty.channel.AbstractChannelHandlerContext.invokeFlush(AbstractChannelHandlerContext.java:768)
at io.netty.channel.AbstractChannelHandlerContext.flush(AbstractChannelHandlerContext.java:749)
at io.netty.channel.ChannelOutboundHandlerAdapter.flush(ChannelOutboundHandlerAdapter.java:115)
at io.netty.channel.AbstractChannelHandlerContext.invokeFlush0(AbstractChannelHandlerContext.java:776)
at io.netty.channel.AbstractChannelHandlerContext.invokeWriteAndFlush(AbstractChannelHandlerContext.java:802)
at io.netty.channel.AbstractChannelHandlerContext.write(AbstractChannelHandlerContext.java:814)
at io.netty.channel.AbstractChannelHandlerContext.writeAndFlush(AbstractChannelHandlerContext.java:794)
at io.netty.channel.AbstractChannelHandlerContext.writeAndFlush(AbstractChannelHandlerContext.java:831)
at io.netty.channel.DefaultChannelPipeline.writeAndFlush(DefaultChannelPipeline.java:1049)
at io.netty.channel.AbstractChannel.writeAndFlush(AbstractChannel.java:300)
at test.operationComplete(test)
at test.operationComplete(test)
at io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:507)
at io.netty.util.concurrent.DefaultPromise.notifyListeners0(DefaultPromise.java:500)
at io.netty.util.concurrent.DefaultPromise.notifyListenersNow(DefaultPromise.java:479)
at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:420)
at io.netty.util.concurrent.DefaultPromise.trySuccess(DefaultPromise.java:104)
at io.netty.channel.DefaultChannelPromise.trySuccess(DefaultChannelPromise.java:84)
at io.netty.channel.kqueue.AbstractKQueueChannel$AbstractKQueueUnsafe.fulfillConnectPromise(AbstractKQueueChannel.java:593)
at io.netty.channel.kqueue.AbstractKQueueChannel$AbstractKQueueUnsafe.finishConnect(AbstractKQueueChannel.java:631)
at io.netty.channel.kqueue.AbstractKQueueChannel$AbstractKQueueUnsafe.writeReady(AbstractKQueueChannel.java:434)
at io.netty.channel.kqueue.KQueueEventLoop.processReady(KQueueEventLoop.java:192)
at io.netty.channel.kqueue.KQueueEventLoop.run(KQueueEventLoop.java:269)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:886)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.UnsupportedOperationException
at io.netty.buffer.ReadOnlyByteBufferBuf.memoryAddress(ReadOnlyByteBufferBuf.java:467)
at io.netty.channel.unix.IovArray.add(IovArray.java:96)
at io.netty.channel.unix.IovArray.processMessage(IovArray.java:191)
at io.netty.channel.ChannelOutboundBuffer.forEachFlushedMessage(ChannelOutboundBuffer.java:762)
at io.netty.channel.kqueue.AbstractKQueueStreamChannel.doWriteMultiple(AbstractKQueueStreamChannel.java:343)
at io.netty.channel.kqueue.AbstractKQueueStreamChannel.doWrite(AbstractKQueueStreamChannel.java:270)
at io.netty.channel.AbstractChannel$AbstractUnsafe.flush0(AbstractChannel.java:934)
... 29 more
Netty version
4.1.20.Final
JVM version (e.g. java -version
)
1.8.0_141
OS version (e.g. uname -a
)
macOS 10.13.2 (also tried on a recent Ubuntu with epoll transport and got a similar result)
Issue Analytics
- State:
- Created 6 years ago
- Comments:8 (7 by maintainers)
Top Results From Across the Web
ByteBuffer (Java Platform SE 7 ) - Oracle Help Center
A byte buffer is either direct or non-direct. Given a direct byte buffer, the Java virtual machine will make a best effort to...
Read more >How to write/read the direct ByteBuffer in the native?
1 Answer 1 ... You can read write to FileDescriptors in Java. However to read/write to the direct buffer all you need to...
Read more >Reliable group communication with JGroups
When true, the ByteBuffer will be created on-heap when unmarshalled, otherwise it will be created off-heap (direct ByteBuffer ).
Read more >Documentation - Apache Kafka
In Kafka the communication between the clients and the servers is done with a simple, high-performance, language agnostic TCP protocol.
Read more >Lettuce Reference Guide
Connection and Queue failures now no longer throw an exception but properly ... Native transport support for Kqueue on macOS systems.
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
@RikkiGibson yes please 😃 We love PRs.
@normanmaurer - https://github.com/netty/netty/commit/7922757575b942d5de5f38d3566857f70b9b4ce6 seems like we missed applying this patch to the duplicate code 😦.
@RikkiGibson - PR sgtm! Make sure you sign the CLA https://netty.io/wiki/developer-guide.html.