Skip to content

Commit

Permalink
add UDP multicast support (#7423)
Browse files Browse the repository at this point in the history
  • Loading branch information
stakach authored and Brian J. Cardiff committed Jun 4, 2019
1 parent b78dfbd commit c94be8b
Show file tree
Hide file tree
Showing 12 changed files with 463 additions and 1 deletion.
60 changes: 59 additions & 1 deletion spec/std/socket/udp_socket_spec.cr
@@ -1,8 +1,9 @@
require "./spec_helper"
require "../../support/errno"
require "socket"

describe UDPSocket do
each_ip_family do |family, address|
each_ip_family do |family, address, unspecified_address|
it "#bind" do
port = unused_local_port
socket = UDPSocket.new(family)
Expand Down Expand Up @@ -52,6 +53,63 @@ describe UDPSocket do
client.close
server.close
end

if {{ flag?(:darwin) }} && family == Socket::Family::INET6
# Darwin is failing to join IPv6 multicast groups on older versions.
# However this is known to work on macOS Mojave with Darwin 18.2.0.
# Darwin also has a bug that prevents selecting the "default" interface.
# https://lists.apple.com/archives/darwin-kernel/2014/Mar/msg00012.html
pending "joins and transmits to multicast groups"
else
it "joins and transmits to multicast groups" do
udp = UDPSocket.new(family)
udp.bind(unspecified_address, 2000)

udp.multicast_loopback = false
udp.multicast_loopback?.should eq(false)

udp.multicast_hops = 4
udp.multicast_hops.should eq(4)
udp.multicast_hops = 0
udp.multicast_hops.should eq(0)

addr = case family
when Socket::Family::INET
expect_raises(Socket::Error, "Unsupported IP address family: INET. For use with IPv6 only") do
udp.multicast_interface 0
end
udp.multicast_interface Socket::IPAddress.new(unspecified_address, 0)

Socket::IPAddress.new("224.0.0.254", 2000)
when Socket::Family::INET6
expect_raises(Socket::Error, "Unsupported IP address family: INET6. For use with IPv4 only") do
udp.multicast_interface(Socket::IPAddress.new(unspecified_address, 0))
end
udp.multicast_interface(0)

Socket::IPAddress.new("ff02::102", 2000)
else
raise "Unsupported IP address family: #{family}"
end

udp.join_group(addr)
udp.multicast_loopback = true
udp.multicast_loopback?.should eq(true)

udp.send("testing", addr)
udp.receive[0].should eq("testing")

udp.leave_group(addr)
udp.send("testing", addr)

# Test that nothing was received after leaving the multicast group
spawn do
sleep 100.milliseconds
udp.close
end
expect_raises_errno(Errno::EBADF, "Error receiving datagram: Bad file descriptor") { udp.receive }
end
end
end

{% if flag?(:linux) %}
Expand Down
26 changes: 26 additions & 0 deletions src/lib_c/aarch64-linux-gnu/c/netinet/in.cr
Expand Up @@ -3,6 +3,7 @@ require "../stdint"

lib LibC
IPPROTO_IP = 0
IPPROTO_IPV6 = 41
IPPROTO_ICMP = 1
IPPROTO_RAW = 255
IPPROTO_TCP = 6
Expand Down Expand Up @@ -39,4 +40,29 @@ lib LibC
sin6_addr : In6Addr
sin6_scope_id : UInt32T
end

IP_MULTICAST_IF = 32
IPV6_MULTICAST_IF = 17

IP_MULTICAST_TTL = 33
IPV6_MULTICAST_HOPS = 18

IP_MULTICAST_LOOP = 34
IPV6_MULTICAST_LOOP = 19

IP_ADD_MEMBERSHIP = 35
IPV6_JOIN_GROUP = 20

IP_DROP_MEMBERSHIP = 36
IPV6_LEAVE_GROUP = 21

struct IpMreq
imr_multiaddr : InAddr
imr_interface : InAddr
end

struct Ipv6Mreq
ipv6mr_multiaddr : In6Addr
ipv6mr_interface : UInt
end
end
26 changes: 26 additions & 0 deletions src/lib_c/aarch64-linux-musl/c/netinet/in.cr
Expand Up @@ -3,6 +3,7 @@ require "../stdint"

lib LibC
IPPROTO_IP = 0
IPPROTO_IPV6 = 41
IPPROTO_ICMP = 1
IPPROTO_RAW = 255
IPPROTO_TCP = 6
Expand Down Expand Up @@ -39,4 +40,29 @@ lib LibC
sin6_addr : In6Addr
sin6_scope_id : UInt32T
end

IP_MULTICAST_IF = 32
IPV6_MULTICAST_IF = 17

IP_MULTICAST_TTL = 33
IPV6_MULTICAST_HOPS = 18

IP_MULTICAST_LOOP = 34
IPV6_MULTICAST_LOOP = 19

IP_ADD_MEMBERSHIP = 35
IPV6_JOIN_GROUP = 20

IP_DROP_MEMBERSHIP = 36
IPV6_LEAVE_GROUP = 21

struct IpMreq
imr_multiaddr : InAddr
imr_interface : InAddr
end

struct Ipv6Mreq
ipv6mr_multiaddr : In6Addr
ipv6mr_interface : UInt
end
end
26 changes: 26 additions & 0 deletions src/lib_c/arm-linux-gnueabihf/c/netinet/in.cr
Expand Up @@ -3,6 +3,7 @@ require "../stdint"

lib LibC
IPPROTO_IP = 0
IPPROTO_IPV6 = 41
IPPROTO_ICMP = 1
IPPROTO_RAW = 255
IPPROTO_TCP = 6
Expand Down Expand Up @@ -39,4 +40,29 @@ lib LibC
sin6_addr : In6Addr
sin6_scope_id : UInt32T
end

IP_MULTICAST_IF = 32
IPV6_MULTICAST_IF = 17

IP_MULTICAST_TTL = 33
IPV6_MULTICAST_HOPS = 18

IP_MULTICAST_LOOP = 34
IPV6_MULTICAST_LOOP = 19

IP_ADD_MEMBERSHIP = 35
IPV6_JOIN_GROUP = 20

IP_DROP_MEMBERSHIP = 36
IPV6_LEAVE_GROUP = 21

struct IpMreq
imr_multiaddr : InAddr
imr_interface : InAddr
end

struct Ipv6Mreq
ipv6mr_multiaddr : In6Addr
ipv6mr_interface : UInt
end
end
26 changes: 26 additions & 0 deletions src/lib_c/i386-linux-gnu/c/netinet/in.cr
Expand Up @@ -3,6 +3,7 @@ require "../stdint"

lib LibC
IPPROTO_IP = 0
IPPROTO_IPV6 = 41
IPPROTO_ICMP = 1
IPPROTO_RAW = 255
IPPROTO_TCP = 6
Expand Down Expand Up @@ -39,4 +40,29 @@ lib LibC
sin6_addr : In6Addr
sin6_scope_id : UInt32T
end

IP_MULTICAST_IF = 32
IPV6_MULTICAST_IF = 17

IP_MULTICAST_TTL = 33
IPV6_MULTICAST_HOPS = 18

IP_MULTICAST_LOOP = 34
IPV6_MULTICAST_LOOP = 19

IP_ADD_MEMBERSHIP = 35
IPV6_JOIN_GROUP = 20

IP_DROP_MEMBERSHIP = 36
IPV6_LEAVE_GROUP = 21

struct IpMreq
imr_multiaddr : InAddr
imr_interface : InAddr
end

struct Ipv6Mreq
ipv6mr_multiaddr : In6Addr
ipv6mr_interface : UInt
end
end
26 changes: 26 additions & 0 deletions src/lib_c/i386-linux-musl/c/netinet/in.cr
Expand Up @@ -3,6 +3,7 @@ require "../stdint"

lib LibC
IPPROTO_IP = 0
IPPROTO_IPV6 = 41
IPPROTO_ICMP = 1
IPPROTO_RAW = 255
IPPROTO_TCP = 6
Expand Down Expand Up @@ -39,4 +40,29 @@ lib LibC
sin6_addr : In6Addr
sin6_scope_id : UInt32T
end

IP_MULTICAST_IF = 32
IPV6_MULTICAST_IF = 17

IP_MULTICAST_TTL = 33
IPV6_MULTICAST_HOPS = 18

IP_MULTICAST_LOOP = 34
IPV6_MULTICAST_LOOP = 19

IP_ADD_MEMBERSHIP = 35
IPV6_JOIN_GROUP = 20

IP_DROP_MEMBERSHIP = 36
IPV6_LEAVE_GROUP = 21

struct IpMreq
imr_multiaddr : InAddr
imr_interface : InAddr
end

struct Ipv6Mreq
ipv6mr_multiaddr : In6Addr
ipv6mr_interface : UInt
end
end
26 changes: 26 additions & 0 deletions src/lib_c/x86_64-darwin/c/netinet/in.cr
Expand Up @@ -3,6 +3,7 @@ require "../stdint"

lib LibC
IPPROTO_IP = 0
IPPROTO_IPV6 = 41
IPPROTO_ICMP = 1
IPPROTO_RAW = 255
IPPROTO_TCP = 6
Expand Down Expand Up @@ -41,4 +42,29 @@ lib LibC
sin6_addr : In6Addr
sin6_scope_id : UInt
end

IP_MULTICAST_IF = 9
IPV6_MULTICAST_IF = 9

IP_MULTICAST_TTL = 10
IPV6_MULTICAST_HOPS = 10

IP_MULTICAST_LOOP = 11
IPV6_MULTICAST_LOOP = 11

IP_ADD_MEMBERSHIP = 12
IPV6_JOIN_GROUP = 12

IP_DROP_MEMBERSHIP = 13
IPV6_LEAVE_GROUP = 13

struct IpMreq
imr_multiaddr : InAddr
imr_interface : InAddr
end

struct Ipv6Mreq
ipv6mr_multiaddr : In6Addr
ipv6mr_interface : UInt
end
end
26 changes: 26 additions & 0 deletions src/lib_c/x86_64-freebsd/c/netinet/in.cr
Expand Up @@ -3,6 +3,7 @@ require "../stdint"

lib LibC
IPPROTO_IP = 0
IPPROTO_IPV6 = 41
IPPROTO_ICMP = 1
IPPROTO_RAW = 255
IPPROTO_TCP = 6
Expand Down Expand Up @@ -41,4 +42,29 @@ lib LibC
sin6_addr : In6Addr
sin6_scope_id : UInt32T
end

IP_MULTICAST_IF = 9
IPV6_MULTICAST_IF = 9

IP_MULTICAST_TTL = 10
IPV6_MULTICAST_HOPS = 10

IP_MULTICAST_LOOP = 11
IPV6_MULTICAST_LOOP = 11

IP_ADD_MEMBERSHIP = 12
IPV6_JOIN_GROUP = 12

IP_DROP_MEMBERSHIP = 13
IPV6_LEAVE_GROUP = 13

struct IpMreq
imr_multiaddr : InAddr
imr_interface : InAddr
end

struct Ipv6Mreq
ipv6mr_multiaddr : In6Addr
ipv6mr_interface : UInt
end
end
26 changes: 26 additions & 0 deletions src/lib_c/x86_64-linux-gnu/c/netinet/in.cr
Expand Up @@ -3,6 +3,7 @@ require "../stdint"

lib LibC
IPPROTO_IP = 0
IPPROTO_IPV6 = 41
IPPROTO_ICMP = 1
IPPROTO_RAW = 255
IPPROTO_TCP = 6
Expand Down Expand Up @@ -39,4 +40,29 @@ lib LibC
sin6_addr : In6Addr
sin6_scope_id : UInt32T
end

IP_MULTICAST_IF = 32
IPV6_MULTICAST_IF = 17

IP_MULTICAST_TTL = 33
IPV6_MULTICAST_HOPS = 18

IP_MULTICAST_LOOP = 34
IPV6_MULTICAST_LOOP = 19

IP_ADD_MEMBERSHIP = 35
IPV6_JOIN_GROUP = 20

IP_DROP_MEMBERSHIP = 36
IPV6_LEAVE_GROUP = 21

struct IpMreq
imr_multiaddr : InAddr
imr_interface : InAddr
end

struct Ipv6Mreq
ipv6mr_multiaddr : In6Addr
ipv6mr_interface : UInt
end
end

0 comments on commit c94be8b

Please sign in to comment.