Project

General

Profile

Bug #13409

UDPSocket#send breaks when using sockaddr

Added by ioquatix (Samuel Williams) about 2 years ago. Updated about 2 years ago.

Status:
Rejected
Priority:
Normal
Assignee:
-
Target version:
-
[ruby-core:80604]

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."

History

Updated by normalperson (Eric Wong) about 2 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 2 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 2 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 2 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 2 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 2 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 2 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 like UDPSocket.new(Socket::AF_INET6).

FYI, Socket#udp_server_loop is useful to implement UDP server which supports both IPv4 and IPv6.

Also available in: Atom PDF