This issue appears to be specific to Windows, and the master branch still has the same behavior as Ruby 2.0. I do not think this is a bug. Windows appears to allow multiple TCP OOB bytes, where most other implements support only a single TCP OOB that can be overwritten. Windows also appears to return successful with 0 bytes if calling recv
with MSG_OOB
, instead of setting errno
to EINVAL
. Additionally, if you pass 1024 as a length to recv
with MSG_OOB
, Windows will apparently wait until that many OOB bytes are available (or until the socket is closed).
Those three things combined result in the behavior, where the first call with MSG_OOB
waits until the client closes the socket, returns both OOB bytes, returns two empty strings for the next two calls with MSG_OOB
, and then returns the non-OOB data in the final call.
You can fix your code by only asking for 1 byte when you call recv
with MSG_OOB
:
require 'socket'
ssc = TCPServer.new '', 9989
sc = ssc.accept
p sc.recv(1024)
p sc.recv(1024)
p sc.recv(1, Socket::MSG_OOB)
p sc.recv(1, Socket::MSG_OOB | Socket::MSG_PEEK)
p sc.recv(1, Socket::MSG_OOB)
p sc.recv(1024)
This will give you the same behavior as ruby 1.9.3.
FWIW, On OpenBSD and Linux, I had to change the server program to get it to run, as the server program as given results in EINVAL errors on both as OOB data is not available (OpenBSD will wait for a packet to be received if there is no data available, Linux apparently will not):
OpenBSD:
require 'socket'
ssc = TCPServer.new '', 9989
sc = ssc.accept
p sc.recv(1024)
p sc.recv(1024, Socket::MSG_OOB)
p sc.recv(1024)
p sc.recv(1024, Socket::MSG_OOB | Socket::MSG_PEEK)
p sc.recv(1024, Socket::MSG_OOB)
p sc.recv(1024)
Linux:
require 'socket'
ssc = TCPServer.new '', 9989
sc = ssc.accept
p sc.recv(1024)
sleep 4
p sc.recv(1024, Socket::MSG_OOB)
p sc.recv(1024)
sleep 2
p sc.recv(1024, Socket::MSG_OOB | Socket::MSG_PEEK)
p sc.recv(1024, Socket::MSG_OOB)
p sc.recv(1024)
With those server programs and the same client program, output is the same on both OpenBSD and Linux:
"1234"
"d"
"abc"
"H"
"H"
"EFG"