github.com/MangoDowner/go-gm@v0.0.0-20180818020936-8baa2bd4408c/src/net/listen_test.go (about) 1 // Copyright 2011 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // +build !plan9 6 7 package net 8 9 import ( 10 "fmt" 11 "internal/testenv" 12 "os" 13 "runtime" 14 "syscall" 15 "testing" 16 ) 17 18 func (ln *TCPListener) port() string { 19 _, port, err := SplitHostPort(ln.Addr().String()) 20 if err != nil { 21 return "" 22 } 23 return port 24 } 25 26 func (c *UDPConn) port() string { 27 _, port, err := SplitHostPort(c.LocalAddr().String()) 28 if err != nil { 29 return "" 30 } 31 return port 32 } 33 34 var tcpListenerTests = []struct { 35 network string 36 address string 37 }{ 38 {"tcp", ""}, 39 {"tcp", "0.0.0.0"}, 40 {"tcp", "::ffff:0.0.0.0"}, 41 {"tcp", "::"}, 42 43 {"tcp", "127.0.0.1"}, 44 {"tcp", "::ffff:127.0.0.1"}, 45 {"tcp", "::1"}, 46 47 {"tcp4", ""}, 48 {"tcp4", "0.0.0.0"}, 49 {"tcp4", "::ffff:0.0.0.0"}, 50 51 {"tcp4", "127.0.0.1"}, 52 {"tcp4", "::ffff:127.0.0.1"}, 53 54 {"tcp6", ""}, 55 {"tcp6", "::"}, 56 57 {"tcp6", "::1"}, 58 } 59 60 // TestTCPListener tests both single and double listen to a test 61 // listener with same address family, same listening address and 62 // same port. 63 func TestTCPListener(t *testing.T) { 64 switch runtime.GOOS { 65 case "plan9": 66 t.Skipf("not supported on %s", runtime.GOOS) 67 } 68 69 for _, tt := range tcpListenerTests { 70 if !testableListenArgs(tt.network, JoinHostPort(tt.address, "0"), "") { 71 t.Logf("skipping %s test", tt.network+" "+tt.address) 72 continue 73 } 74 75 ln1, err := Listen(tt.network, JoinHostPort(tt.address, "0")) 76 if err != nil { 77 t.Fatal(err) 78 } 79 if err := checkFirstListener(tt.network, ln1); err != nil { 80 ln1.Close() 81 t.Fatal(err) 82 } 83 ln2, err := Listen(tt.network, JoinHostPort(tt.address, ln1.(*TCPListener).port())) 84 if err == nil { 85 ln2.Close() 86 } 87 if err := checkSecondListener(tt.network, tt.address, err); err != nil { 88 ln1.Close() 89 t.Fatal(err) 90 } 91 ln1.Close() 92 } 93 } 94 95 var udpListenerTests = []struct { 96 network string 97 address string 98 }{ 99 {"udp", ""}, 100 {"udp", "0.0.0.0"}, 101 {"udp", "::ffff:0.0.0.0"}, 102 {"udp", "::"}, 103 104 {"udp", "127.0.0.1"}, 105 {"udp", "::ffff:127.0.0.1"}, 106 {"udp", "::1"}, 107 108 {"udp4", ""}, 109 {"udp4", "0.0.0.0"}, 110 {"udp4", "::ffff:0.0.0.0"}, 111 112 {"udp4", "127.0.0.1"}, 113 {"udp4", "::ffff:127.0.0.1"}, 114 115 {"udp6", ""}, 116 {"udp6", "::"}, 117 118 {"udp6", "::1"}, 119 } 120 121 // TestUDPListener tests both single and double listen to a test 122 // listener with same address family, same listening address and 123 // same port. 124 func TestUDPListener(t *testing.T) { 125 switch runtime.GOOS { 126 case "plan9": 127 t.Skipf("not supported on %s", runtime.GOOS) 128 } 129 130 for _, tt := range udpListenerTests { 131 if !testableListenArgs(tt.network, JoinHostPort(tt.address, "0"), "") { 132 t.Logf("skipping %s test", tt.network+" "+tt.address) 133 continue 134 } 135 136 c1, err := ListenPacket(tt.network, JoinHostPort(tt.address, "0")) 137 if err != nil { 138 t.Fatal(err) 139 } 140 if err := checkFirstListener(tt.network, c1); err != nil { 141 c1.Close() 142 t.Fatal(err) 143 } 144 c2, err := ListenPacket(tt.network, JoinHostPort(tt.address, c1.(*UDPConn).port())) 145 if err == nil { 146 c2.Close() 147 } 148 if err := checkSecondListener(tt.network, tt.address, err); err != nil { 149 c1.Close() 150 t.Fatal(err) 151 } 152 c1.Close() 153 } 154 } 155 156 var dualStackTCPListenerTests = []struct { 157 network1, address1 string // first listener 158 network2, address2 string // second listener 159 xerr error // expected error value, nil or other 160 }{ 161 // Test cases and expected results for the attempting 2nd listen on the same port 162 // 1st listen 2nd listen darwin freebsd linux openbsd 163 // ------------------------------------------------------------------------------------ 164 // "tcp" "" "tcp" "" - - - - 165 // "tcp" "" "tcp" "0.0.0.0" - - - - 166 // "tcp" "0.0.0.0" "tcp" "" - - - - 167 // ------------------------------------------------------------------------------------ 168 // "tcp" "" "tcp" "[::]" - - - ok 169 // "tcp" "[::]" "tcp" "" - - - ok 170 // "tcp" "0.0.0.0" "tcp" "[::]" - - - ok 171 // "tcp" "[::]" "tcp" "0.0.0.0" - - - ok 172 // "tcp" "[::ffff:0.0.0.0]" "tcp" "[::]" - - - ok 173 // "tcp" "[::]" "tcp" "[::ffff:0.0.0.0]" - - - ok 174 // ------------------------------------------------------------------------------------ 175 // "tcp4" "" "tcp6" "" ok ok ok ok 176 // "tcp6" "" "tcp4" "" ok ok ok ok 177 // "tcp4" "0.0.0.0" "tcp6" "[::]" ok ok ok ok 178 // "tcp6" "[::]" "tcp4" "0.0.0.0" ok ok ok ok 179 // ------------------------------------------------------------------------------------ 180 // "tcp" "127.0.0.1" "tcp" "[::1]" ok ok ok ok 181 // "tcp" "[::1]" "tcp" "127.0.0.1" ok ok ok ok 182 // "tcp4" "127.0.0.1" "tcp6" "[::1]" ok ok ok ok 183 // "tcp6" "[::1]" "tcp4" "127.0.0.1" ok ok ok ok 184 // 185 // Platform default configurations: 186 // darwin, kernel version 11.3.0 187 // net.inet6.ip6.v6only=0 (overridable by sysctl or IPV6_V6ONLY option) 188 // freebsd, kernel version 8.2 189 // net.inet6.ip6.v6only=1 (overridable by sysctl or IPV6_V6ONLY option) 190 // linux, kernel version 3.0.0 191 // net.ipv6.bindv6only=0 (overridable by sysctl or IPV6_V6ONLY option) 192 // openbsd, kernel version 5.0 193 // net.inet6.ip6.v6only=1 (overriding is prohibited) 194 195 {"tcp", "", "tcp", "", syscall.EADDRINUSE}, 196 {"tcp", "", "tcp", "0.0.0.0", syscall.EADDRINUSE}, 197 {"tcp", "0.0.0.0", "tcp", "", syscall.EADDRINUSE}, 198 199 {"tcp", "", "tcp", "::", syscall.EADDRINUSE}, 200 {"tcp", "::", "tcp", "", syscall.EADDRINUSE}, 201 {"tcp", "0.0.0.0", "tcp", "::", syscall.EADDRINUSE}, 202 {"tcp", "::", "tcp", "0.0.0.0", syscall.EADDRINUSE}, 203 {"tcp", "::ffff:0.0.0.0", "tcp", "::", syscall.EADDRINUSE}, 204 {"tcp", "::", "tcp", "::ffff:0.0.0.0", syscall.EADDRINUSE}, 205 206 {"tcp4", "", "tcp6", "", nil}, 207 {"tcp6", "", "tcp4", "", nil}, 208 {"tcp4", "0.0.0.0", "tcp6", "::", nil}, 209 {"tcp6", "::", "tcp4", "0.0.0.0", nil}, 210 211 {"tcp", "127.0.0.1", "tcp", "::1", nil}, 212 {"tcp", "::1", "tcp", "127.0.0.1", nil}, 213 {"tcp4", "127.0.0.1", "tcp6", "::1", nil}, 214 {"tcp6", "::1", "tcp4", "127.0.0.1", nil}, 215 } 216 217 // TestDualStackTCPListener tests both single and double listen 218 // to a test listener with various address families, different 219 // listening address and same port. 220 // 221 // On DragonFly BSD, we expect the kernel version of node under test 222 // to be greater than or equal to 4.4. 223 func TestDualStackTCPListener(t *testing.T) { 224 switch runtime.GOOS { 225 case "nacl", "plan9": 226 t.Skipf("not supported on %s", runtime.GOOS) 227 } 228 if !supportsIPv4() || !supportsIPv6() { 229 t.Skip("both IPv4 and IPv6 are required") 230 } 231 232 for _, tt := range dualStackTCPListenerTests { 233 if !testableListenArgs(tt.network1, JoinHostPort(tt.address1, "0"), "") { 234 t.Logf("skipping %s test", tt.network1+" "+tt.address1) 235 continue 236 } 237 238 if !supportsIPv4map() && differentWildcardAddr(tt.address1, tt.address2) { 239 tt.xerr = nil 240 } 241 var firstErr, secondErr error 242 for i := 0; i < 5; i++ { 243 lns, err := newDualStackListener() 244 if err != nil { 245 t.Fatal(err) 246 } 247 port := lns[0].port() 248 for _, ln := range lns { 249 ln.Close() 250 } 251 var ln1 Listener 252 ln1, firstErr = Listen(tt.network1, JoinHostPort(tt.address1, port)) 253 if firstErr != nil { 254 continue 255 } 256 if err := checkFirstListener(tt.network1, ln1); err != nil { 257 ln1.Close() 258 t.Fatal(err) 259 } 260 ln2, err := Listen(tt.network2, JoinHostPort(tt.address2, ln1.(*TCPListener).port())) 261 if err == nil { 262 ln2.Close() 263 } 264 if secondErr = checkDualStackSecondListener(tt.network2, tt.address2, err, tt.xerr); secondErr != nil { 265 ln1.Close() 266 continue 267 } 268 ln1.Close() 269 break 270 } 271 if firstErr != nil { 272 t.Error(firstErr) 273 } 274 if secondErr != nil { 275 t.Error(secondErr) 276 } 277 } 278 } 279 280 var dualStackUDPListenerTests = []struct { 281 network1, address1 string // first listener 282 network2, address2 string // second listener 283 xerr error // expected error value, nil or other 284 }{ 285 {"udp", "", "udp", "", syscall.EADDRINUSE}, 286 {"udp", "", "udp", "0.0.0.0", syscall.EADDRINUSE}, 287 {"udp", "0.0.0.0", "udp", "", syscall.EADDRINUSE}, 288 289 {"udp", "", "udp", "::", syscall.EADDRINUSE}, 290 {"udp", "::", "udp", "", syscall.EADDRINUSE}, 291 {"udp", "0.0.0.0", "udp", "::", syscall.EADDRINUSE}, 292 {"udp", "::", "udp", "0.0.0.0", syscall.EADDRINUSE}, 293 {"udp", "::ffff:0.0.0.0", "udp", "::", syscall.EADDRINUSE}, 294 {"udp", "::", "udp", "::ffff:0.0.0.0", syscall.EADDRINUSE}, 295 296 {"udp4", "", "udp6", "", nil}, 297 {"udp6", "", "udp4", "", nil}, 298 {"udp4", "0.0.0.0", "udp6", "::", nil}, 299 {"udp6", "::", "udp4", "0.0.0.0", nil}, 300 301 {"udp", "127.0.0.1", "udp", "::1", nil}, 302 {"udp", "::1", "udp", "127.0.0.1", nil}, 303 {"udp4", "127.0.0.1", "udp6", "::1", nil}, 304 {"udp6", "::1", "udp4", "127.0.0.1", nil}, 305 } 306 307 // TestDualStackUDPListener tests both single and double listen 308 // to a test listener with various address families, different 309 // listening address and same port. 310 // 311 // On DragonFly BSD, we expect the kernel version of node under test 312 // to be greater than or equal to 4.4. 313 func TestDualStackUDPListener(t *testing.T) { 314 switch runtime.GOOS { 315 case "nacl", "plan9": 316 t.Skipf("not supported on %s", runtime.GOOS) 317 } 318 if !supportsIPv4() || !supportsIPv6() { 319 t.Skip("both IPv4 and IPv6 are required") 320 } 321 322 for _, tt := range dualStackUDPListenerTests { 323 if !testableListenArgs(tt.network1, JoinHostPort(tt.address1, "0"), "") { 324 t.Logf("skipping %s test", tt.network1+" "+tt.address1) 325 continue 326 } 327 328 if !supportsIPv4map() && differentWildcardAddr(tt.address1, tt.address2) { 329 tt.xerr = nil 330 } 331 var firstErr, secondErr error 332 for i := 0; i < 5; i++ { 333 cs, err := newDualStackPacketListener() 334 if err != nil { 335 t.Fatal(err) 336 } 337 port := cs[0].port() 338 for _, c := range cs { 339 c.Close() 340 } 341 var c1 PacketConn 342 c1, firstErr = ListenPacket(tt.network1, JoinHostPort(tt.address1, port)) 343 if firstErr != nil { 344 continue 345 } 346 if err := checkFirstListener(tt.network1, c1); err != nil { 347 c1.Close() 348 t.Fatal(err) 349 } 350 c2, err := ListenPacket(tt.network2, JoinHostPort(tt.address2, c1.(*UDPConn).port())) 351 if err == nil { 352 c2.Close() 353 } 354 if secondErr = checkDualStackSecondListener(tt.network2, tt.address2, err, tt.xerr); secondErr != nil { 355 c1.Close() 356 continue 357 } 358 c1.Close() 359 break 360 } 361 if firstErr != nil { 362 t.Error(firstErr) 363 } 364 if secondErr != nil { 365 t.Error(secondErr) 366 } 367 } 368 } 369 370 func differentWildcardAddr(i, j string) bool { 371 if (i == "" || i == "0.0.0.0" || i == "::ffff:0.0.0.0") && (j == "" || j == "0.0.0.0" || j == "::ffff:0.0.0.0") { 372 return false 373 } 374 if i == "[::]" && j == "[::]" { 375 return false 376 } 377 return true 378 } 379 380 func checkFirstListener(network string, ln interface{}) error { 381 switch network { 382 case "tcp": 383 fd := ln.(*TCPListener).fd 384 if err := checkDualStackAddrFamily(fd); err != nil { 385 return err 386 } 387 case "tcp4": 388 fd := ln.(*TCPListener).fd 389 if fd.family != syscall.AF_INET { 390 return fmt.Errorf("%v got %v; want %v", fd.laddr, fd.family, syscall.AF_INET) 391 } 392 case "tcp6": 393 fd := ln.(*TCPListener).fd 394 if fd.family != syscall.AF_INET6 { 395 return fmt.Errorf("%v got %v; want %v", fd.laddr, fd.family, syscall.AF_INET6) 396 } 397 case "udp": 398 fd := ln.(*UDPConn).fd 399 if err := checkDualStackAddrFamily(fd); err != nil { 400 return err 401 } 402 case "udp4": 403 fd := ln.(*UDPConn).fd 404 if fd.family != syscall.AF_INET { 405 return fmt.Errorf("%v got %v; want %v", fd.laddr, fd.family, syscall.AF_INET) 406 } 407 case "udp6": 408 fd := ln.(*UDPConn).fd 409 if fd.family != syscall.AF_INET6 { 410 return fmt.Errorf("%v got %v; want %v", fd.laddr, fd.family, syscall.AF_INET6) 411 } 412 default: 413 return UnknownNetworkError(network) 414 } 415 return nil 416 } 417 418 func checkSecondListener(network, address string, err error) error { 419 switch network { 420 case "tcp", "tcp4", "tcp6": 421 if err == nil { 422 return fmt.Errorf("%s should fail", network+" "+address) 423 } 424 case "udp", "udp4", "udp6": 425 if err == nil { 426 return fmt.Errorf("%s should fail", network+" "+address) 427 } 428 default: 429 return UnknownNetworkError(network) 430 } 431 return nil 432 } 433 434 func checkDualStackSecondListener(network, address string, err, xerr error) error { 435 switch network { 436 case "tcp", "tcp4", "tcp6": 437 if xerr == nil && err != nil || xerr != nil && err == nil { 438 return fmt.Errorf("%s got %v; want %v", network+" "+address, err, xerr) 439 } 440 case "udp", "udp4", "udp6": 441 if xerr == nil && err != nil || xerr != nil && err == nil { 442 return fmt.Errorf("%s got %v; want %v", network+" "+address, err, xerr) 443 } 444 default: 445 return UnknownNetworkError(network) 446 } 447 return nil 448 } 449 450 func checkDualStackAddrFamily(fd *netFD) error { 451 switch a := fd.laddr.(type) { 452 case *TCPAddr: 453 // If a node under test supports both IPv6 capability 454 // and IPv6 IPv4-mapping capability, we can assume 455 // that the node listens on a wildcard address with an 456 // AF_INET6 socket. 457 if supportsIPv4map() && fd.laddr.(*TCPAddr).isWildcard() { 458 if fd.family != syscall.AF_INET6 { 459 return fmt.Errorf("Listen(%s, %v) returns %v; want %v", fd.net, fd.laddr, fd.family, syscall.AF_INET6) 460 } 461 } else { 462 if fd.family != a.family() { 463 return fmt.Errorf("Listen(%s, %v) returns %v; want %v", fd.net, fd.laddr, fd.family, a.family()) 464 } 465 } 466 case *UDPAddr: 467 // If a node under test supports both IPv6 capability 468 // and IPv6 IPv4-mapping capability, we can assume 469 // that the node listens on a wildcard address with an 470 // AF_INET6 socket. 471 if supportsIPv4map() && fd.laddr.(*UDPAddr).isWildcard() { 472 if fd.family != syscall.AF_INET6 { 473 return fmt.Errorf("ListenPacket(%s, %v) returns %v; want %v", fd.net, fd.laddr, fd.family, syscall.AF_INET6) 474 } 475 } else { 476 if fd.family != a.family() { 477 return fmt.Errorf("ListenPacket(%s, %v) returns %v; want %v", fd.net, fd.laddr, fd.family, a.family()) 478 } 479 } 480 default: 481 return fmt.Errorf("unexpected protocol address type: %T", a) 482 } 483 return nil 484 } 485 486 func TestWildWildcardListener(t *testing.T) { 487 testenv.MustHaveExternalNetwork(t) 488 489 switch runtime.GOOS { 490 case "plan9": 491 t.Skipf("not supported on %s", runtime.GOOS) 492 } 493 494 defer func() { 495 if p := recover(); p != nil { 496 t.Fatalf("panicked: %v", p) 497 } 498 }() 499 500 if ln, err := Listen("tcp", ""); err == nil { 501 ln.Close() 502 } 503 if ln, err := ListenPacket("udp", ""); err == nil { 504 ln.Close() 505 } 506 if ln, err := ListenTCP("tcp", nil); err == nil { 507 ln.Close() 508 } 509 if ln, err := ListenUDP("udp", nil); err == nil { 510 ln.Close() 511 } 512 if ln, err := ListenIP("ip:icmp", nil); err == nil { 513 ln.Close() 514 } 515 } 516 517 var ipv4MulticastListenerTests = []struct { 518 net string 519 gaddr *UDPAddr // see RFC 4727 520 }{ 521 {"udp", &UDPAddr{IP: IPv4(224, 0, 0, 254), Port: 12345}}, 522 523 {"udp4", &UDPAddr{IP: IPv4(224, 0, 0, 254), Port: 12345}}, 524 } 525 526 // TestIPv4MulticastListener tests both single and double listen to a 527 // test listener with same address family, same group address and same 528 // port. 529 func TestIPv4MulticastListener(t *testing.T) { 530 testenv.MustHaveExternalNetwork(t) 531 532 switch runtime.GOOS { 533 case "android", "nacl", "plan9": 534 t.Skipf("not supported on %s", runtime.GOOS) 535 case "solaris": 536 t.Skipf("not supported on solaris, see golang.org/issue/7399") 537 } 538 if !supportsIPv4() { 539 t.Skip("IPv4 is not supported") 540 } 541 542 closer := func(cs []*UDPConn) { 543 for _, c := range cs { 544 if c != nil { 545 c.Close() 546 } 547 } 548 } 549 550 for _, ifi := range []*Interface{loopbackInterface(), nil} { 551 // Note that multicast interface assignment by system 552 // is not recommended because it usually relies on 553 // routing stuff for finding out an appropriate 554 // nexthop containing both network and link layer 555 // adjacencies. 556 if ifi == nil || !*testIPv4 { 557 continue 558 } 559 for _, tt := range ipv4MulticastListenerTests { 560 var err error 561 cs := make([]*UDPConn, 2) 562 if cs[0], err = ListenMulticastUDP(tt.net, ifi, tt.gaddr); err != nil { 563 t.Fatal(err) 564 } 565 if err := checkMulticastListener(cs[0], tt.gaddr.IP); err != nil { 566 closer(cs) 567 t.Fatal(err) 568 } 569 if cs[1], err = ListenMulticastUDP(tt.net, ifi, tt.gaddr); err != nil { 570 closer(cs) 571 t.Fatal(err) 572 } 573 if err := checkMulticastListener(cs[1], tt.gaddr.IP); err != nil { 574 closer(cs) 575 t.Fatal(err) 576 } 577 closer(cs) 578 } 579 } 580 } 581 582 var ipv6MulticastListenerTests = []struct { 583 net string 584 gaddr *UDPAddr // see RFC 4727 585 }{ 586 {"udp", &UDPAddr{IP: ParseIP("ff01::114"), Port: 12345}}, 587 {"udp", &UDPAddr{IP: ParseIP("ff02::114"), Port: 12345}}, 588 {"udp", &UDPAddr{IP: ParseIP("ff04::114"), Port: 12345}}, 589 {"udp", &UDPAddr{IP: ParseIP("ff05::114"), Port: 12345}}, 590 {"udp", &UDPAddr{IP: ParseIP("ff08::114"), Port: 12345}}, 591 {"udp", &UDPAddr{IP: ParseIP("ff0e::114"), Port: 12345}}, 592 593 {"udp6", &UDPAddr{IP: ParseIP("ff01::114"), Port: 12345}}, 594 {"udp6", &UDPAddr{IP: ParseIP("ff02::114"), Port: 12345}}, 595 {"udp6", &UDPAddr{IP: ParseIP("ff04::114"), Port: 12345}}, 596 {"udp6", &UDPAddr{IP: ParseIP("ff05::114"), Port: 12345}}, 597 {"udp6", &UDPAddr{IP: ParseIP("ff08::114"), Port: 12345}}, 598 {"udp6", &UDPAddr{IP: ParseIP("ff0e::114"), Port: 12345}}, 599 } 600 601 // TestIPv6MulticastListener tests both single and double listen to a 602 // test listener with same address family, same group address and same 603 // port. 604 func TestIPv6MulticastListener(t *testing.T) { 605 testenv.MustHaveExternalNetwork(t) 606 607 switch runtime.GOOS { 608 case "plan9": 609 t.Skipf("not supported on %s", runtime.GOOS) 610 case "solaris": 611 t.Skipf("not supported on solaris, see issue 7399") 612 } 613 if !supportsIPv6() { 614 t.Skip("IPv6 is not supported") 615 } 616 if os.Getuid() != 0 { 617 t.Skip("must be root") 618 } 619 620 closer := func(cs []*UDPConn) { 621 for _, c := range cs { 622 if c != nil { 623 c.Close() 624 } 625 } 626 } 627 628 for _, ifi := range []*Interface{loopbackInterface(), nil} { 629 // Note that multicast interface assignment by system 630 // is not recommended because it usually relies on 631 // routing stuff for finding out an appropriate 632 // nexthop containing both network and link layer 633 // adjacencies. 634 if ifi == nil && !*testIPv6 { 635 continue 636 } 637 for _, tt := range ipv6MulticastListenerTests { 638 var err error 639 cs := make([]*UDPConn, 2) 640 if cs[0], err = ListenMulticastUDP(tt.net, ifi, tt.gaddr); err != nil { 641 t.Fatal(err) 642 } 643 if err := checkMulticastListener(cs[0], tt.gaddr.IP); err != nil { 644 closer(cs) 645 t.Fatal(err) 646 } 647 if cs[1], err = ListenMulticastUDP(tt.net, ifi, tt.gaddr); err != nil { 648 closer(cs) 649 t.Fatal(err) 650 } 651 if err := checkMulticastListener(cs[1], tt.gaddr.IP); err != nil { 652 closer(cs) 653 t.Fatal(err) 654 } 655 closer(cs) 656 } 657 } 658 } 659 660 func checkMulticastListener(c *UDPConn, ip IP) error { 661 if ok, err := multicastRIBContains(ip); err != nil { 662 return err 663 } else if !ok { 664 return fmt.Errorf("%s not found in multicast rib", ip.String()) 665 } 666 la := c.LocalAddr() 667 if la, ok := la.(*UDPAddr); !ok || la.Port == 0 { 668 return fmt.Errorf("got %v; want a proper address with non-zero port number", la) 669 } 670 return nil 671 } 672 673 func multicastRIBContains(ip IP) (bool, error) { 674 switch runtime.GOOS { 675 case "dragonfly", "netbsd", "openbsd", "plan9", "solaris", "windows": 676 return true, nil // not implemented yet 677 case "linux": 678 if runtime.GOARCH == "arm" || runtime.GOARCH == "alpha" { 679 return true, nil // not implemented yet 680 } 681 } 682 ift, err := Interfaces() 683 if err != nil { 684 return false, err 685 } 686 for _, ifi := range ift { 687 ifmat, err := ifi.MulticastAddrs() 688 if err != nil { 689 return false, err 690 } 691 for _, ifma := range ifmat { 692 if ifma.(*IPAddr).IP.Equal(ip) { 693 return true, nil 694 } 695 } 696 } 697 return false, nil 698 }