jnr/jnr-unixsocket

Async write incorrectly consumes buffer when hitting flow control

gregw opened this issue · 1 comments

gregw commented

When writing data asynchronously to the point of hitting flow control, the UnixSocketChannel.write method correctly returns 0 bytes written, but it incorrectly updates the ByteBuffer position so that the bytes are consumed.

The problem is demonstrated by this class in the eclipse jetty project. The test is a bit verbose, as it first confirms that client and server channels are working asynchronously. It then writes large buffers until flow controlled and the bug is indicated by the incorrect remaining value of the buffer after the write of 0 bytes.

I get the following output:

serverChannel=jnr.unixsocket.UnixServerSocketChannel@4dfa3a9d,
client=jnr.unixsocket.UnixSocketChannel@3fee9989 connected=true pending=false
serverSelected=1 [jnr.enxio.channels.PollSelectionKey@146ba0ac]
key=jnr.enxio.channels.PollSelectionKey@146ba0ac/SERVER c=false a=true r=false w=false
server=jnr.unixsocket.UnixSocketChannel@7085bdee connected=true pending=false
serverSelected=0 []
server read=0
clientSelected=0 []
client wrote=5
serverSelected=1 [jnr.enxio.channels.PollSelectionKey@73ad2d6]
key=jnr.enxio.channels.PollSelectionKey@73ad2d6/server c=false a=false r=true w=false ch=jnr.unixsocket.UnixSocketChannel@7085bdee
server read=5 'Hello'
clientSelected=0 []
server wrote=5
clientSelected=0 []
clientSelected=1 [jnr.enxio.channels.PollSelectionKey@2f686d1f]
key=jnr.enxio.channels.PollSelectionKey@2f686d1f/client c=false a=false r=true w=false ch=jnr.unixsocket.UnixSocketChannel@3fee9989
client read=5 'Ciao!'
So far so good.... now it gets strange...
server wrote 32768/32768 remaining=0
server wrote 32768/32768 remaining=0
server wrote 32768/32768 remaining=0
server wrote 32768/32768 remaining=0
server wrote 32768/32768 remaining=0
server wrote 32768/32768 remaining=0
server wrote 32768/32768 remaining=0
server wrote 0/32768 remaining=0
BUG!!!!!!!!!!!!!!!!
server wrote 229376 before flow control
clientSelected=1 [jnr.enxio.channels.PollSelectionKey@2f686d1f]
key=jnr.enxio.channels.PollSelectionKey@2f686d1f/client c=false a=false r=true w=false ch=jnr.unixsocket.UnixSocketChannel@3fee9989
client read=32 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
gregw commented

The problem is at https://github.com/jnr/jnr-unixsocket/blob/master/src/main/java/jnr/enxio/channels/Common.java#L97

The passed buffer is consumed by the put even if not all the data is eventually written. Either the copy should be avoided (see #48 ) or at least the position should be updated using the number of bytes actually written.