Project

General

Profile

Actions

Bug #19012

open

BasicSocket#recv* methods return an empty packet instead of nil on closed connections

Added by byroot (Jean Boussier) 3 months ago. Updated 4 days ago.

Status:
Open
Priority:
Normal
Assignee:
-
Target version:
-
[ruby-core:109961]

Description

man recvmsg(2) states:

Return Value
These calls return the number of bytes received, or -1 if an error occurred. The return value will be 0 when the peer has performed an orderly shutdown.

But somehow the entire receiv family of methods in Ruby seem to interpret 0 as empty string instead of "EOF".

require 'socket'

puts "=== pipes ==="
r, w = IO.pipe
r.read_nonblock(1, exception: false) # => :wait_readable
w.close
r.read_nonblock(1, exception: false) # => nil (EOF)

puts "=== sockets ===="
r, w = UNIXSocket.socketpair
r.read_nonblock(1, exception: false) # => :wait_readable
r.recvmsg_nonblock(1, exception: false) # => :wait_readable
r.recv_nonblock(1, exception: false) # => :wait_readable

w.close

r.read_nonblock(1, exception: false) # => nil (EOF)
r.recvmsg_nonblock(1, exception: false) # => ["", #<Addrinfo: empty-sockaddr SOCK_STREAM>, 128]]
r.recvmsg # => ["", #<Addrinfo: empty-sockaddr SOCK_STREAM>, 0]]
r.recv_nonblock(1, exception: false) # => ""

Expected behavior

I would expect recvmsg_nonblock, recvmsg, recv_nonblock and recv to return nil when the connection is closed.

Updated by byroot (Jean Boussier) 3 months ago

@akr (Akira Tanaka) pointed on the PR that this behavior might be desirable for "connection-less" sockets such as DGRAM.

That said I think we should try to distinguish between "nothing was received" and "we received an empty packet".

I'm not quite familiar enough with recv (yet) to know whether it's possible to make the difference though. I'll try to research this more when I have a bit of time.

Updated by mame (Yusuke Endoh) 5 days ago

This is what @akr (Akira Tanaka) said at the dev meeting. (My understanding)

The proposed behavior might be possible for stream. On the other hand, for datagram, the current behavior is better. I am not sure if there is a portable way to determine if the file descriptor behind an IO object is stream or datagram.

Updated by byroot (Jean Boussier) 4 days ago

I am not sure if there is a portable way to determine if the file descriptor behind an IO object is stream or datagram.

Yeah, me neither. I'll try to dig more.

Updated by byroot (Jean Boussier) 4 days ago

Apparently we can get this via getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &length);, the question being how portable it is.

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0