Bug #8219
closedruby 2.0.0-p0 socket.recv MSG_OOB problem?
Description
server1.rb¶
require 'socket'
ssc = TCPServer.new '', 9989
sc = ssc.accept
p sc.recv(1024)
p sc.recv(1024)
ruby 2.0.0p0: has OOB data, not return until remote send data again or close¶
p sc.recv(1024, Socket::MSG_OOB)
p sc.recv(1024, Socket::MSG_OOB | Socket::MSG_PEEK)
p sc.recv(1024, Socket::MSG_OOB)
p sc.recv(1024)
client1.rb¶
require 'socket'
sc=TCPSocket.new '127.0.0.1', 9989
sc.send '1234', 0
sleep 1.5
sc.send 'abcd', Socket::MSG_OOB
sleep 3
sc.send 'EFGH', Socket::MSG_OOB
sleep 1.5
Use ruby 2.0.0p0 run above server1 code, output is
"1234"
"abc"
"dH"
""
""
"EFG"
,
use ruby 1.9.3p327 or python or c code, output is
"1234"
"abc"
"d"
"H"
"H"
"EFG"
Is this has a bug?
Updated by naruse (Yui NARUSE) almost 11 years ago
- Tracker changed from Backport to Bug
- Project changed from Backport200 to Ruby master
- Status changed from Open to Assigned
- Assignee set to MartinBosslet (Martin Bosslet)
Updated by zzak (zzak _) over 8 years ago
- Assignee changed from MartinBosslet (Martin Bosslet) to 7150
Updated by jeremyevans0 (Jeremy Evans) over 4 years ago
- Status changed from Assigned to Rejected
- Assignee deleted (
7150)
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"