Project

General

Profile

Bug #8219

ruby 2.0.0-p0 socket.recv MSG_OOB problem?

Added by windwiny (wind winy) over 6 years ago. Updated 2 months ago.

Status:
Rejected
Priority:
Normal
Assignee:
-
Target version:
-
ruby -v:
Backport:
[ruby-core:53997]

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?

History

#1

Updated by naruse (Yui NARUSE) over 6 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)
#2

Updated by zzak (Zachary Scott) about 4 years ago

  • Assignee changed from MartinBosslet (Martin Bosslet) to openssl

Updated by jeremyevans0 (Jeremy Evans) 2 months ago

  • Assignee deleted (openssl)
  • Status changed from Assigned to Rejected

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"

Also available in: Atom PDF