Skip to content

Commit

Permalink
Showing 21 changed files with 226 additions and 73 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@ Bug fixes:
* Fixed `Array#to_h` so it doesn't set a default value (#1698).
* Removed extra `public` methods on `IO` (#1702).
* Fixed `Process.kill(signal, Process.pid)` when the signal is trapped as `:IGNORE` (#1702).
* Fixed `Addrinfo.new(String)` to reliably find the address family (#1702).

Compatibility:

@@ -16,6 +17,7 @@ Compatibility:
* Implemented more `Ripper` methods as no-ops (#1694).
* Implemented `rb_enc_sprintf` (#1702).
* Implemented `ENV#{filter,filter!}` aliases for `select` and `select!`.
* Non-blocking `StringIO` and `Socket` APIs now support `exception: false` like MRI (#1702).

Changes:

23 changes: 8 additions & 15 deletions lib/truffle/socket/addrinfo.rb
Original file line number Diff line number Diff line change
@@ -106,17 +106,14 @@ def initialize(sockaddr, pfamily = nil, socktype = 0, protocol = 0)
pfamily = Socket::PF_INET6
end
else
if sockaddr.bytesize == Truffle::Socket::Foreign::SockaddrUn.size
@afamily = Truffle::Socket::Foreign::Sockaddr.family_of_string(sockaddr)
case @afamily
when Socket::AF_UNIX
@unix_path = Socket.unpack_sockaddr_un(sockaddr)
@afamily = Socket::AF_UNIX
else
when Socket::AF_INET
@ip_port, @ip_address = Socket.unpack_sockaddr_in(sockaddr)
when Socket::AF_INET6
@ip_port, @ip_address = Socket.unpack_sockaddr_in(sockaddr)

if sockaddr.bytesize == Truffle::Socket::Foreign::SockaddrIn6.size
@afamily = Socket::AF_INET6
else
@afamily = Socket::AF_INET
end
end
end

@@ -203,17 +200,13 @@ def ip?
end

def ip_address
unless ip?
raise SocketError, 'An IPv4/IPv6 address is required'
end
raise SocketError, 'need IPv4 or IPv6 address' unless ip?

@ip_address
end

def ip_port
unless ip?
raise SocketError, 'An IPv4/IPv6 address is required'
end
raise SocketError, 'need IPv4 or IPv6 address' unless ip?

@ip_port
end
70 changes: 52 additions & 18 deletions lib/truffle/socket/basic_socket.rb
Original file line number Diff line number Diff line change
@@ -155,15 +155,37 @@ def send(message, flags, dest_sockaddr = nil)
bytes_sent
end

def recv(bytes_to_read, flags = 0)
private def internal_recv(bytes_to_read, flags, buffer, exception)
raise ArgumentError, 'buffer argument not yet supported' if buffer

Truffle::Socket::Foreign.memory_pointer(bytes_to_read) do |buf|
n_bytes = Truffle::Socket::Foreign.recv(@descriptor, buf, bytes_to_read, flags)
Errno.handle('recv(2)') if n_bytes == -1

if n_bytes == -1
if exception
Truffle::Socket::Error.read_error('recv(2)', self)
else
return :wait_readable
end
end

return buf.read_string(n_bytes)
end
end

def recvmsg(max_msg_len = nil, flags = 0, *_)
def recv(bytes_to_read, flags = 0, buf = nil)
internal_recv(bytes_to_read, flags, buf, true)
end

def recv_nonblock(bytes_to_read, flags = 0, buf = nil, exception: true)
fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK)

Truffle::Socket::Error.wrap_read_nonblock do
internal_recv(bytes_to_read, flags, buf, exception)
end
end

private def internal_recvmsg(max_msg_len, flags, max_control_len, scm_rights, exception)
socket_type = getsockopt(:SOCKET, :TYPE).int

if socket_type == Socket::SOCK_STREAM
@@ -188,7 +210,13 @@ def recvmsg(max_msg_len = nil, flags = 0, *_)
msg_size = Truffle::Socket::Foreign
.recvmsg(@descriptor, header.pointer, flags)

Truffle::Socket::Error.read_error('recvmsg(2)', self) if msg_size < 0
if msg_size < 0
if exception
Truffle::Socket::Error.read_error('recvmsg(2)', self)
else
return :wait_readable
end
end

if grow_msg and header.message_truncated?
need_more = true
@@ -216,13 +244,17 @@ def recvmsg(max_msg_len = nil, flags = 0, *_)
nil
end

def recvmsg_nonblock(max_msg_len = nil, flags = 0, *_)
def recvmsg(max_msg_len = nil, flags = 0, max_control_len = nil, scm_rights: false)
internal_recvmsg(max_msg_len, flags, max_control_len, scm_rights, true)
end

def recvmsg_nonblock(max_msg_len = nil, flags = 0, max_control_len = nil, exception: true, scm_rights: false)
fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK)

recvmsg(max_msg_len, flags | Socket::MSG_DONTWAIT)
internal_recvmsg(max_msg_len, flags | Socket::MSG_DONTWAIT, max_control_len, scm_rights, exception)
end

def sendmsg(message, flags = 0, dest_sockaddr = nil, *_)
private def internal_sendmsg(message, flags, dest_sockaddr, exception)
msg_buffer = Truffle::Socket::Foreign.char_pointer(message.bytesize)
io_vec = Truffle::Socket::Foreign::Iovec.with_buffer(msg_buffer)
header = Truffle::Socket::Foreign::Msghdr.new
@@ -247,7 +279,13 @@ def sendmsg(message, flags = 0, dest_sockaddr = nil, *_)
num_bytes = Truffle::Socket::Foreign
.sendmsg(@descriptor, header.pointer, flags)

Truffle::Socket::Error.read_error('sendmsg(2)', self) if num_bytes < 0
if num_bytes < 0
if exception
Truffle::Socket::Error.read_error('sendmsg(2)', self)
else
return :wait_writable
end
end

num_bytes
ensure
@@ -258,10 +296,14 @@ def sendmsg(message, flags = 0, dest_sockaddr = nil, *_)
end
end

def sendmsg_nonblock(message, flags = 0, dest_sockaddr = nil, *_)
def sendmsg(message, flags = 0, dest_sockaddr = nil, *controls)
internal_sendmsg(message, flags, dest_sockaddr, true)
end

def sendmsg_nonblock(message, flags = 0, dest_sockaddr = nil, *controls, exception: true)
fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK)

sendmsg(message, flags | Socket::MSG_DONTWAIT, dest_sockaddr)
internal_sendmsg(message, flags | Socket::MSG_DONTWAIT, dest_sockaddr, exception)
end

def close_read
@@ -292,14 +334,6 @@ def close_write
nil
end

def recv_nonblock(bytes_to_read, flags = 0)
fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK)

Truffle::Socket::Error.wrap_read_nonblock do
recv(bytes_to_read, flags)
end
end

def shutdown(how = Socket::SHUT_RDWR)
how = Truffle::Socket.shutdown_option(how)
err = Truffle::Socket::Foreign.shutdown(@descriptor, how)
11 changes: 8 additions & 3 deletions lib/truffle/socket/ip_socket.rb
Original file line number Diff line number Diff line change
@@ -39,10 +39,10 @@ def peeraddr(reverse_lookup=nil)
Truffle::Socket.address_info(:getpeername, self, reverse_lookup)
end

def recvfrom(maxlen, flags = 0)
flags = 0 if flags.nil?
private def internal_recvfrom(maxlen, flags, exception)
message, addr = internal_recvmsg(maxlen, flags, nil, false, exception)

message, addr = recvmsg(maxlen, flags)
return message if message == :wait_readable

aname = Truffle::Socket.address_family_name(addr.afamily)
hostname = addr.ip_address
@@ -60,4 +60,9 @@ def recvfrom(maxlen, flags = 0)

[message, [aname, addr.ip_port, hostname, addr.ip_address]]
end

def recvfrom(maxlen, flags = 0)
flags = 0 if flags.nil?
internal_recvfrom(maxlen, flags, true)
end
end
21 changes: 16 additions & 5 deletions lib/truffle/socket/socket.rb
Original file line number Diff line number Diff line change
@@ -251,9 +251,16 @@ def self.socketpair(family, type, protocol = 0)
family = Truffle::Socket.address_family(family)
type = Truffle::Socket.socket_type(type)

fd0, fd1 = Truffle::Socket::Foreign.socketpair(family, type, protocol)
fd1, fd2 = Truffle::Socket::Foreign.socketpair(family, type, protocol)

[for_fd(fd0), for_fd(fd1)]
s1 = for_fd(fd1)
s2 = for_fd(fd2)

[s1, s2].map do |sock|
sock.instance_variable_set(:@family, family)
sock.instance_variable_set(:@socket_type, type)
sock
end
end

class << self
@@ -377,10 +384,14 @@ def recvfrom(bytes, flags = 0)
[message, addr]
end

def recvfrom_nonblock(bytes, flags = 0)
message, addr = recvmsg_nonblock(bytes, flags)
def recvfrom_nonblock(bytes, flags = 0, exception: true)
message, addr = recvmsg_nonblock(bytes, flags, exception: exception)

[message, addr]
if message == :wait_readable
message
else
[message, addr]
end
end

def listen(backlog)
25 changes: 14 additions & 11 deletions lib/truffle/socket/truffle.rb
Original file line number Diff line number Diff line change
@@ -66,7 +66,7 @@ def self.sockaddr_class_for_socket(socket)
end
end

def self.accept(source, new_class)
def self.internal_accept(source, new_class, exception)
raise IOError, 'socket has been closed' if source.closed?

sockaddr = sockaddr_class_for_socket(source).new
@@ -79,7 +79,13 @@ def self.accept(source, new_class)
.accept(source.fileno, sockaddr.pointer, size_p)
end

Error.read_error('accept(2)', source) if fd < 0
if fd < 0
if exception
Error.read_error('accept(2)', source)
else
return :wait_readable
end
end

socket = new_class.for_fd(fd)

@@ -91,19 +97,16 @@ def self.accept(source, new_class)
sockaddr.free
end
end
private_class_method :internal_accept

def self.accept(source, new_class)
internal_accept(source, new_class, true)
end

def self.accept_nonblock(source, new_class, exception)
source.fcntl(::Fcntl::F_SETFL, ::Fcntl::O_NONBLOCK)

begin
accept(source, new_class)
rescue Errno::EAGAIN
if exception
raise ::IO::EAGAINWaitReadable
else
return :wait_readable
end
end
internal_accept(source, new_class, exception)
end

def self.listen(source, backlog)
2 changes: 1 addition & 1 deletion lib/truffle/socket/truffle/foreign.rb
Original file line number Diff line number Diff line change
@@ -304,7 +304,7 @@ def self.unpack_sockaddr_in(sockaddr, reverse_lookup)

# On some systems this doesn't fail for families other than AF_INET(6)
# so we raise manually here.
unless family =~ /AF_INET/
unless family.include?('AF_INET')
raise ArgumentError, 'not an AF_INET/AF_INET6 sockaddr'
end

20 changes: 17 additions & 3 deletions lib/truffle/socket/truffle/foreign/sockaddr.rb
Original file line number Diff line number Diff line change
@@ -28,16 +28,30 @@ module Truffle
module Socket
module Foreign
class Sockaddr < Truffle::FFI::Struct
config('platform.sockaddr', :sa_data, :sa_family)
config('platform.sockaddr', :sa_family, :sa_data)

def data
self[:sa_data]
SA_FAMILY_T = Truffle::Config['platform.typedef.sa_family_t'].to_sym
SA_FAMILY_OFFSET = Truffle::Config['platform.sockaddr.sa_family.offset']

def self.family_of_string(str)
case SA_FAMILY_T
when :ushort
str[SA_FAMILY_OFFSET..-1].unpack1('S')
when :uchar
str[SA_FAMILY_OFFSET..-1].unpack1('C')
else
raise "Unexpected type for sa_family_t: #{SA_FAMILY_T}"
end
end

def family
self[:sa_family]
end

def data
self[:sa_data]
end

def to_s
pointer.read_string(self.class.size)
end
6 changes: 2 additions & 4 deletions lib/truffle/socket/udp_socket.rb
Original file line number Diff line number Diff line change
@@ -71,14 +71,12 @@ def send(message, flags, host = nil, port = nil)
super(message, flags, addr)
end

def recvfrom_nonblock(maxlen, flags = 0)
def recvfrom_nonblock(maxlen, flags = 0, exception: true)
fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK)

flags = 0 if flags.nil?

flags |= Socket::MSG_DONTWAIT

recvfrom(maxlen, flags)
internal_recvfrom(maxlen, flags | Socket::MSG_DONTWAIT, exception)
end

def inspect
8 changes: 6 additions & 2 deletions lib/truffle/socket/unix_server.rb
Original file line number Diff line number Diff line change
@@ -49,11 +49,15 @@ def listen(backlog)
end

def accept
Truffle::Socket.accept(self, UNIXSocket)[0]
socket, _ = Truffle::Socket.accept(self, UNIXSocket)

socket
end

def accept_nonblock(exception: true)
Truffle::Socket.accept_nonblock(self, UNIXSocket, exception)[0]
socket, _ = Truffle::Socket.accept_nonblock(self, UNIXSocket, exception)

socket
end

def sysaccept
Loading

0 comments on commit fa9863d

Please sign in to comment.