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