1
2
3
4
5 package ipv4_test
6
7 import (
8 "net"
9 "runtime"
10 "testing"
11
12 "golang.org/x/net/ipv4"
13 "golang.org/x/net/nettest"
14 )
15
16 var packetConnMulticastSocketOptionTests = []struct {
17 net, proto, addr string
18 grp, src net.Addr
19 }{
20 {"udp4", "", "224.0.0.0:0", &net.UDPAddr{IP: net.IPv4(224, 0, 0, 249)}, nil},
21 {"ip4", ":icmp", "0.0.0.0", &net.IPAddr{IP: net.IPv4(224, 0, 0, 250)}, nil},
22
23 {"udp4", "", "232.0.0.0:0", &net.UDPAddr{IP: net.IPv4(232, 0, 1, 249)}, &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1)}},
24 {"ip4", ":icmp", "0.0.0.0", &net.IPAddr{IP: net.IPv4(232, 0, 1, 250)}, &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1)}},
25 }
26
27 func TestPacketConnMulticastSocketOptions(t *testing.T) {
28 switch runtime.GOOS {
29 case "fuchsia", "hurd", "js", "nacl", "plan9", "wasip1", "zos":
30 t.Skipf("not supported on %s", runtime.GOOS)
31 }
32 ifi, err := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagMulticast|net.FlagLoopback)
33 if err != nil {
34 t.Skipf("not available on %s", runtime.GOOS)
35 }
36
37 ok := nettest.SupportsRawSocket()
38 for _, tt := range packetConnMulticastSocketOptionTests {
39 if tt.net == "ip4" && !ok {
40 t.Logf("not supported on %s/%s", runtime.GOOS, runtime.GOARCH)
41 continue
42 }
43 c, err := net.ListenPacket(tt.net+tt.proto, tt.addr)
44 if err != nil {
45 t.Fatal(err)
46 }
47 defer c.Close()
48 p := ipv4.NewPacketConn(c)
49 defer p.Close()
50
51 if tt.src == nil {
52 testMulticastSocketOptions(t, p, ifi, tt.grp)
53 } else {
54 testSourceSpecificMulticastSocketOptions(t, p, ifi, tt.grp, tt.src)
55 }
56 }
57 }
58
59 var rawConnMulticastSocketOptionTests = []struct {
60 grp, src net.Addr
61 }{
62 {&net.IPAddr{IP: net.IPv4(224, 0, 0, 250)}, nil},
63
64 {&net.IPAddr{IP: net.IPv4(232, 0, 1, 250)}, &net.IPAddr{IP: net.IPv4(127, 0, 0, 1)}},
65 }
66
67 func TestRawConnMulticastSocketOptions(t *testing.T) {
68 if !nettest.SupportsRawSocket() {
69 t.Skipf("not supported on %s/%s", runtime.GOOS, runtime.GOARCH)
70 }
71 ifi, err := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagMulticast|net.FlagLoopback)
72 if err != nil {
73 t.Skipf("not available on %s", runtime.GOOS)
74 }
75
76 for _, tt := range rawConnMulticastSocketOptionTests {
77 c, err := net.ListenPacket("ip4:icmp", "0.0.0.0")
78 if err != nil {
79 t.Fatal(err)
80 }
81 defer c.Close()
82 r, err := ipv4.NewRawConn(c)
83 if err != nil {
84 t.Fatal(err)
85 }
86 defer r.Close()
87
88 if tt.src == nil {
89 testMulticastSocketOptions(t, r, ifi, tt.grp)
90 } else {
91 testSourceSpecificMulticastSocketOptions(t, r, ifi, tt.grp, tt.src)
92 }
93 }
94 }
95
96 type testIPv4MulticastConn interface {
97 MulticastTTL() (int, error)
98 SetMulticastTTL(ttl int) error
99 MulticastLoopback() (bool, error)
100 SetMulticastLoopback(bool) error
101 JoinGroup(*net.Interface, net.Addr) error
102 LeaveGroup(*net.Interface, net.Addr) error
103 JoinSourceSpecificGroup(*net.Interface, net.Addr, net.Addr) error
104 LeaveSourceSpecificGroup(*net.Interface, net.Addr, net.Addr) error
105 ExcludeSourceSpecificGroup(*net.Interface, net.Addr, net.Addr) error
106 IncludeSourceSpecificGroup(*net.Interface, net.Addr, net.Addr) error
107 }
108
109 func testMulticastSocketOptions(t *testing.T, c testIPv4MulticastConn, ifi *net.Interface, grp net.Addr) {
110 t.Helper()
111
112 const ttl = 255
113 if err := c.SetMulticastTTL(ttl); err != nil {
114 t.Error(err)
115 return
116 }
117 if v, err := c.MulticastTTL(); err != nil {
118 t.Error(err)
119 return
120 } else if v != ttl {
121 t.Errorf("got %v; want %v", v, ttl)
122 return
123 }
124
125 for _, toggle := range []bool{true, false} {
126 if err := c.SetMulticastLoopback(toggle); err != nil {
127 t.Error(err)
128 return
129 }
130 if v, err := c.MulticastLoopback(); err != nil {
131 t.Error(err)
132 return
133 } else if v != toggle {
134 t.Errorf("got %v; want %v", v, toggle)
135 return
136 }
137 }
138
139 if err := c.JoinGroup(ifi, grp); err != nil {
140 t.Error(err)
141 return
142 }
143 if err := c.LeaveGroup(ifi, grp); err != nil {
144 t.Error(err)
145 return
146 }
147 }
148
149 func testSourceSpecificMulticastSocketOptions(t *testing.T, c testIPv4MulticastConn, ifi *net.Interface, grp, src net.Addr) {
150 t.Helper()
151
152
153 if err := c.JoinGroup(ifi, grp); err != nil {
154 t.Error(err)
155 return
156 }
157 if err := c.ExcludeSourceSpecificGroup(ifi, grp, src); err != nil {
158 switch runtime.GOOS {
159 case "freebsd", "linux":
160 default:
161 t.Logf("not supported on %s", runtime.GOOS)
162 return
163 }
164 t.Error(err)
165 return
166 }
167 if err := c.IncludeSourceSpecificGroup(ifi, grp, src); err != nil {
168 t.Error(err)
169 return
170 }
171 if err := c.LeaveGroup(ifi, grp); err != nil {
172 t.Error(err)
173 return
174 }
175
176
177 if err := c.JoinSourceSpecificGroup(ifi, grp, src); err != nil {
178 t.Error(err)
179 return
180 }
181 if err := c.LeaveSourceSpecificGroup(ifi, grp, src); err != nil {
182 t.Error(err)
183 return
184 }
185
186
187 if err := c.JoinSourceSpecificGroup(ifi, grp, src); err != nil {
188 t.Error(err)
189 return
190 }
191 if err := c.LeaveGroup(ifi, grp); err != nil {
192 t.Error(err)
193 return
194 }
195 }
196
View as plain text