Bug #13409
closedUDPSocket#send breaks when using sockaddr
Description
Here is the working example.
#!/usr/bin/env ruby
require 'socket'
port = 6778
server = UDPSocket.new.tap{|socket| socket.bind("localhost", port)}
client = UDPSocket.new
data = "Matz is nice so we are nice."
t1 = Thread.new do
packet, (_, remote_port, remote_host) = server.recvfrom(512)
server.send(packet, 0, remote_host, remote_port)
end
t2 = Thread.new do
client.send(data, 0, "localhost", port)
response, _ = client.recvfrom(512)
puts "Got response: #{response.inspect}"
end
[t1, t2].each(&:join)
puts "Finished."
Here is one that fails with EINVAL:
#!/usr/bin/env ruby
Thread.abort_on_exception = true
require 'socket'
port = 6778
server = UDPSocket.new.tap{|socket| socket.bind("localhost", port)}
client = UDPSocket.new
data = "Matz is nice so we are nice."
t1 = Thread.new do
puts "Server waiting for packet..."
packet, (_, remote_port, remote_host) = server.recvfrom(512)
server.send(packet, 0, remote_host, remote_port)
end
t2 = Thread.new do
address = Addrinfo.udp("localhost", port)
puts "Sending data to #{address.inspect}"
# Should call ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen), but calls send which fails with EINVAL.
result = client.send(data, 0, address.to_sockaddr)
response, _ = client.recvfrom(512)
puts "Got response: #{response.inspect}"
end
[t1, t2].each(&:join)
puts "Finished."
Updated by normalperson (Eric Wong) about 7 years ago
samuel@oriontransfer.org wrote:
Here is one that fails with EINVAL:
Thanks for the example. This failure appears OS-specific,
no problems under Linux.
Updated by ioquatix (Samuel Williams) about 7 years ago
On linux I get the following output for the 2nd example:
Server waiting for packet...
Sending data to #<Addrinfo: [::1]:6778 UDP (localhost)>
-:25:in `send': Address family not supported by protocol - send(2) (Errno::EAFNOSUPPORT)
from -:25:in `block in <main>'
Updated by nobu (Nobuyoshi Nakada) about 7 years ago
rsock_bsock_send
calls sendto(2)
if the third argument is present and not nil.
Fixed the message now.
Updated by nobu (Nobuyoshi Nakada) about 7 years ago
- Description updated (diff)
On 2017/04/07 15:44, Eric Wong wrote:
It looks like your system does not have full IPv6 support.
What version is your kernel?
Updated by ioquatix (Samuel Williams) about 7 years ago
% uname -a
Linux koyoko.local 4.10.4-1-ARCH #1 SMP PREEMPT Sat Mar 18 19:39:18 CET 2017 x86_64 GNU/Linux
% ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eno1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 74:d0:2b:7b:dd:77 brd ff:ff:ff:ff:ff:ff
inet 192.168.1.23/24 brd 192.168.1.255 scope global dynamic eno1
valid_lft 383sec preferred_lft 383sec
inet6 2406:e007:aed:0:76d0:2bff:fe7b:dd77/64 scope global noprefixroute dynamic
valid_lft 2591868sec preferred_lft 604668sec
inet6 fe80::76d0:2bff:fe7b:dd77/64 scope link
valid_lft forever preferred_lft forever
I use IPv6 all the time and it works fine.
Updated by naruse (Yui NARUSE) about 7 years ago
- Status changed from Open to Rejected
server = UDPSocket.new.tap{|socket| socket.bind("localhost", port)}
client = UDPSocket.new
UDPSocket.new
receives an optional argument address family, whose default is AF_INET.
If you use IPv6, you need to specify AF_INET6 like UDPSocket.new(Socket::AF_INET6)
.
Updated by naruse (Yui NARUSE) about 7 years ago
naruse (Yui NARUSE) wrote:
UDPSocket.new
receives an optional argument address family, whose default is AF_INET.
If you use IPv6, you need to specify AF_INET6 likeUDPSocket.new(Socket::AF_INET6)
.
FYI, Socket#udp_server_loop is useful to implement UDP server which supports both IPv4 and IPv6.