Skip to content

Commit 654041a

Browse files
committed
Fix Addrinfo.new(String) to reliably find the address family
* By reading `sa_family` from the `struct sockaddr` (see `man 2 bind`). This is also what MRI does. Note that the `sa_family` is at a non-zero offset on macOS. * Match MRI for error messages. * Set family and socket_type for Socket.pair.
1 parent a442034 commit 654041a

File tree

4 files changed

+32
-18
lines changed

4 files changed

+32
-18
lines changed

lib/truffle/socket/addrinfo.rb

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -106,17 +106,14 @@ def initialize(sockaddr, pfamily = nil, socktype = 0, protocol = 0)
106106
pfamily = Socket::PF_INET6
107107
end
108108
else
109-
if sockaddr.bytesize == Truffle::Socket::Foreign::SockaddrUn.size
109+
@afamily = Truffle::Socket::Foreign::Sockaddr.family_of_string(sockaddr)
110+
case @afamily
111+
when Socket::AF_UNIX
110112
@unix_path = Socket.unpack_sockaddr_un(sockaddr)
111-
@afamily = Socket::AF_UNIX
112-
else
113+
when Socket::AF_INET
114+
@ip_port, @ip_address = Socket.unpack_sockaddr_in(sockaddr)
115+
when Socket::AF_INET6
113116
@ip_port, @ip_address = Socket.unpack_sockaddr_in(sockaddr)
114-
115-
if sockaddr.bytesize == Truffle::Socket::Foreign::SockaddrIn6.size
116-
@afamily = Socket::AF_INET6
117-
else
118-
@afamily = Socket::AF_INET
119-
end
120117
end
121118
end
122119

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

205202
def ip_address
206-
unless ip?
207-
raise SocketError, 'An IPv4/IPv6 address is required'
208-
end
203+
raise SocketError, 'need IPv4 or IPv6 address' unless ip?
209204

210205
@ip_address
211206
end
212207

213208
def ip_port
214-
unless ip?
215-
raise SocketError, 'An IPv4/IPv6 address is required'
216-
end
209+
raise SocketError, 'need IPv4 or IPv6 address' unless ip?
217210

218211
@ip_port
219212
end

lib/truffle/socket/socket.rb

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -251,9 +251,16 @@ def self.socketpair(family, type, protocol = 0)
251251
family = Truffle::Socket.address_family(family)
252252
type = Truffle::Socket.socket_type(type)
253253

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

256-
[for_fd(fd0), for_fd(fd1)]
256+
s1 = for_fd(fd1)
257+
s2 = for_fd(fd2)
258+
259+
[s1, s2].map do |sock|
260+
sock.instance_variable_set(:@family, family)
261+
sock.instance_variable_set(:@socket_type, type)
262+
sock
263+
end
257264
end
258265

259266
class << self

lib/truffle/socket/truffle/foreign.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ def self.unpack_sockaddr_in(sockaddr, reverse_lookup)
304304

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

lib/truffle/socket/truffle/foreign/sockaddr.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,20 @@ module Foreign
3030
class Sockaddr < Truffle::FFI::Struct
3131
config('platform.sockaddr', :sa_data, :sa_family)
3232

33+
SA_FAMILY_T = Truffle::Config['platform.typedef.sa_family_t'].to_sym
34+
SA_FAMILY_OFFSET = Truffle::Config['platform.sockaddr.sa_family.offset']
35+
36+
def self.family_of_string(str)
37+
case SA_FAMILY_T
38+
when :ushort
39+
str[SA_FAMILY_OFFSET..-1].unpack1('S')
40+
when :uchar
41+
str[SA_FAMILY_OFFSET..-1].unpack1('C')
42+
else
43+
raise "Unexpected type for sa_family_t: #{SA_FAMILY_T}"
44+
end
45+
end
46+
3347
def data
3448
self[:sa_data]
3549
end

0 commit comments

Comments
 (0)