2011-08-17 11:28:29 -06:00
|
|
|
// Copyright 2009 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
2011-12-21 03:44:47 -07:00
|
|
|
// +build darwin freebsd linux netbsd openbsd windows
|
build: add build comments to core packages
The go/build package already recognizes
system-specific file names like
mycode_darwin.go
mycode_darwin_386.go
mycode_386.s
However, it is also common to write files that
apply to multiple architectures, so a recent CL added
to go/build the ability to process comments
listing a set of conditions for building. For example:
// +build darwin freebsd openbsd/386
says that this file should be compiled only on
OS X, FreeBSD, or 32-bit x86 OpenBSD systems.
These conventions are not yet documented
(hence this long CL description).
This CL adds build comments to the multi-system
files in the core library, a step toward making it
possible to use go/build to build them.
With this change go/build can handle crypto/rand,
exec, net, path/filepath, os/user, and time.
os and syscall need additional adjustments.
R=golang-dev, r, gri, r, gustavo
CC=golang-dev
https://golang.org/cl/5011046
2011-09-15 14:48:57 -06:00
|
|
|
|
2011-08-17 11:28:29 -06:00
|
|
|
package net
|
|
|
|
|
2012-11-08 09:35:16 -07:00
|
|
|
import (
|
|
|
|
"syscall"
|
|
|
|
"time"
|
|
|
|
)
|
2012-01-26 09:31:42 -07:00
|
|
|
|
2011-08-17 11:28:29 -06:00
|
|
|
func sockaddrToUDP(sa syscall.Sockaddr) Addr {
|
|
|
|
switch sa := sa.(type) {
|
|
|
|
case *syscall.SockaddrInet4:
|
net, cmd/fix: add IPv6 scoped addressing zone to INET, INET6 address structs
This CL starts to introduce IPv6 scoped addressing capability
into the net package.
The Public API changes are:
+pkg net, type IPAddr struct, Zone string
+pkg net, type IPNet struct, Zone string
+pkg net, type TCPAddr struct, Zone string
+pkg net, type UDPAddr struct, Zone string
Update #4234.
R=rsc, bradfitz, iant
CC=golang-dev
https://golang.org/cl/6849045
2012-11-26 08:45:42 -07:00
|
|
|
return &UDPAddr{IP: sa.Addr[0:], Port: sa.Port}
|
2011-08-17 11:28:29 -06:00
|
|
|
case *syscall.SockaddrInet6:
|
net, cmd/fix: add IPv6 scoped addressing zone to INET, INET6 address structs
This CL starts to introduce IPv6 scoped addressing capability
into the net package.
The Public API changes are:
+pkg net, type IPAddr struct, Zone string
+pkg net, type IPNet struct, Zone string
+pkg net, type TCPAddr struct, Zone string
+pkg net, type UDPAddr struct, Zone string
Update #4234.
R=rsc, bradfitz, iant
CC=golang-dev
https://golang.org/cl/6849045
2012-11-26 08:45:42 -07:00
|
|
|
return &UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneToString(int(sa.ZoneId))}
|
2011-08-17 11:28:29 -06:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *UDPAddr) family() int {
|
2011-08-24 11:59:33 -06:00
|
|
|
if a == nil || len(a.IP) <= IPv4len {
|
2011-08-17 11:28:29 -06:00
|
|
|
return syscall.AF_INET
|
|
|
|
}
|
|
|
|
if a.IP.To4() != nil {
|
|
|
|
return syscall.AF_INET
|
|
|
|
}
|
|
|
|
return syscall.AF_INET6
|
|
|
|
}
|
|
|
|
|
2012-03-05 08:13:10 -07:00
|
|
|
func (a *UDPAddr) isWildcard() bool {
|
|
|
|
if a == nil || a.IP == nil {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return a.IP.IsUnspecified()
|
|
|
|
}
|
|
|
|
|
2011-11-01 20:05:34 -06:00
|
|
|
func (a *UDPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
|
2013-08-02 22:32:22 -06:00
|
|
|
if a == nil {
|
|
|
|
return nil, nil
|
|
|
|
}
|
net, cmd/fix: add IPv6 scoped addressing zone to INET, INET6 address structs
This CL starts to introduce IPv6 scoped addressing capability
into the net package.
The Public API changes are:
+pkg net, type IPAddr struct, Zone string
+pkg net, type IPNet struct, Zone string
+pkg net, type TCPAddr struct, Zone string
+pkg net, type UDPAddr struct, Zone string
Update #4234.
R=rsc, bradfitz, iant
CC=golang-dev
https://golang.org/cl/6849045
2012-11-26 08:45:42 -07:00
|
|
|
return ipToSockaddr(family, a.IP, a.Port, a.Zone)
|
2011-08-17 11:28:29 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
func (a *UDPAddr) toAddr() sockaddr {
|
2013-08-02 22:32:22 -06:00
|
|
|
if a == nil {
|
|
|
|
return nil
|
2011-08-17 11:28:29 -06:00
|
|
|
}
|
|
|
|
return a
|
|
|
|
}
|
|
|
|
|
2013-03-31 01:47:54 -06:00
|
|
|
// UDPConn is the implementation of the Conn and PacketConn interfaces
|
|
|
|
// for UDP network connections.
|
2011-08-17 11:28:29 -06:00
|
|
|
type UDPConn struct {
|
net: consolidate common socket functions
In resolving 3507, the fix had to be applied individually to
the four *Conn types, tcp, udp, rawip and unix, due to the
duplicate code in each Conn type.
This CL consolidates the common net.Conn methods that all four
*Conn types implement into a base conn type.
Pros:
* The fix for 3507 would have only needed to be applied to one
method. Further improvements, such as possibly removing the
c.fd != nil check in c.ok(), would benefit from this CL.
* Nearly 300 lines removed from the net package.
* The public interface and documentation are not changed.
* I think this is an excellent example of the power of embedding.
Cons:
* The net package is already distributed over many files, this
CL adds another place to look.
* The fix for 3507 was a total of 16 lines changed, this follow
up CL could be considered to be an overreaction as new Conn types
are unlikely to be added in the near future.
R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/6098047
2012-04-27 06:17:08 -06:00
|
|
|
conn
|
2011-08-17 11:28:29 -06:00
|
|
|
}
|
|
|
|
|
net: consolidate common socket functions
In resolving 3507, the fix had to be applied individually to
the four *Conn types, tcp, udp, rawip and unix, due to the
duplicate code in each Conn type.
This CL consolidates the common net.Conn methods that all four
*Conn types implement into a base conn type.
Pros:
* The fix for 3507 would have only needed to be applied to one
method. Further improvements, such as possibly removing the
c.fd != nil check in c.ok(), would benefit from this CL.
* Nearly 300 lines removed from the net package.
* The public interface and documentation are not changed.
* I think this is an excellent example of the power of embedding.
Cons:
* The net package is already distributed over many files, this
CL adds another place to look.
* The fix for 3507 was a total of 16 lines changed, this follow
up CL could be considered to be an overreaction as new Conn types
are unlikely to be added in the near future.
R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/6098047
2012-04-27 06:17:08 -06:00
|
|
|
func newUDPConn(fd *netFD) *UDPConn { return &UDPConn{conn{fd}} }
|
2011-08-17 11:28:29 -06:00
|
|
|
|
|
|
|
// ReadFromUDP reads a UDP packet from c, copying the payload into b.
|
|
|
|
// It returns the number of bytes copied into b and the return address
|
|
|
|
// that was on the packet.
|
|
|
|
//
|
2013-03-31 01:47:54 -06:00
|
|
|
// ReadFromUDP can be made to time out and return an error with
|
|
|
|
// Timeout() == true after a fixed time limit; see SetDeadline and
|
|
|
|
// SetReadDeadline.
|
2011-11-01 20:05:34 -06:00
|
|
|
func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) {
|
2011-08-17 11:28:29 -06:00
|
|
|
if !c.ok() {
|
2012-02-16 16:04:29 -07:00
|
|
|
return 0, nil, syscall.EINVAL
|
2011-08-17 11:28:29 -06:00
|
|
|
}
|
|
|
|
n, sa, err := c.fd.ReadFrom(b)
|
|
|
|
switch sa := sa.(type) {
|
|
|
|
case *syscall.SockaddrInet4:
|
net, cmd/fix: add IPv6 scoped addressing zone to INET, INET6 address structs
This CL starts to introduce IPv6 scoped addressing capability
into the net package.
The Public API changes are:
+pkg net, type IPAddr struct, Zone string
+pkg net, type IPNet struct, Zone string
+pkg net, type TCPAddr struct, Zone string
+pkg net, type UDPAddr struct, Zone string
Update #4234.
R=rsc, bradfitz, iant
CC=golang-dev
https://golang.org/cl/6849045
2012-11-26 08:45:42 -07:00
|
|
|
addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port}
|
2011-08-17 11:28:29 -06:00
|
|
|
case *syscall.SockaddrInet6:
|
net, cmd/fix: add IPv6 scoped addressing zone to INET, INET6 address structs
This CL starts to introduce IPv6 scoped addressing capability
into the net package.
The Public API changes are:
+pkg net, type IPAddr struct, Zone string
+pkg net, type IPNet struct, Zone string
+pkg net, type TCPAddr struct, Zone string
+pkg net, type UDPAddr struct, Zone string
Update #4234.
R=rsc, bradfitz, iant
CC=golang-dev
https://golang.org/cl/6849045
2012-11-26 08:45:42 -07:00
|
|
|
addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneToString(int(sa.ZoneId))}
|
2011-08-17 11:28:29 -06:00
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2012-01-29 03:11:05 -07:00
|
|
|
// ReadFrom implements the PacketConn ReadFrom method.
|
2012-01-31 09:53:26 -07:00
|
|
|
func (c *UDPConn) ReadFrom(b []byte) (int, Addr, error) {
|
2011-08-17 11:28:29 -06:00
|
|
|
if !c.ok() {
|
2012-02-16 16:04:29 -07:00
|
|
|
return 0, nil, syscall.EINVAL
|
2011-08-17 11:28:29 -06:00
|
|
|
}
|
net, cmd/fix: add IPv6 scoped addressing zone to INET, INET6 address structs
This CL starts to introduce IPv6 scoped addressing capability
into the net package.
The Public API changes are:
+pkg net, type IPAddr struct, Zone string
+pkg net, type IPNet struct, Zone string
+pkg net, type TCPAddr struct, Zone string
+pkg net, type UDPAddr struct, Zone string
Update #4234.
R=rsc, bradfitz, iant
CC=golang-dev
https://golang.org/cl/6849045
2012-11-26 08:45:42 -07:00
|
|
|
n, addr, err := c.ReadFromUDP(b)
|
|
|
|
return n, addr.toAddr(), err
|
2011-08-17 11:28:29 -06:00
|
|
|
}
|
|
|
|
|
2012-09-24 15:57:32 -06:00
|
|
|
// ReadMsgUDP reads a packet from c, copying the payload into b and
|
2013-03-20 17:32:37 -06:00
|
|
|
// the associated out-of-band data into oob. It returns the number
|
2012-09-24 15:57:32 -06:00
|
|
|
// of bytes copied into b, the number of bytes copied into oob, the
|
|
|
|
// flags that were set on the packet and the source address of the
|
|
|
|
// packet.
|
|
|
|
func (c *UDPConn) ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, err error) {
|
|
|
|
if !c.ok() {
|
|
|
|
return 0, 0, 0, nil, syscall.EINVAL
|
|
|
|
}
|
|
|
|
var sa syscall.Sockaddr
|
|
|
|
n, oobn, flags, sa, err = c.fd.ReadMsg(b, oob)
|
|
|
|
switch sa := sa.(type) {
|
|
|
|
case *syscall.SockaddrInet4:
|
net, cmd/fix: add IPv6 scoped addressing zone to INET, INET6 address structs
This CL starts to introduce IPv6 scoped addressing capability
into the net package.
The Public API changes are:
+pkg net, type IPAddr struct, Zone string
+pkg net, type IPNet struct, Zone string
+pkg net, type TCPAddr struct, Zone string
+pkg net, type UDPAddr struct, Zone string
Update #4234.
R=rsc, bradfitz, iant
CC=golang-dev
https://golang.org/cl/6849045
2012-11-26 08:45:42 -07:00
|
|
|
addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port}
|
2012-09-24 15:57:32 -06:00
|
|
|
case *syscall.SockaddrInet6:
|
net, cmd/fix: add IPv6 scoped addressing zone to INET, INET6 address structs
This CL starts to introduce IPv6 scoped addressing capability
into the net package.
The Public API changes are:
+pkg net, type IPAddr struct, Zone string
+pkg net, type IPNet struct, Zone string
+pkg net, type TCPAddr struct, Zone string
+pkg net, type UDPAddr struct, Zone string
Update #4234.
R=rsc, bradfitz, iant
CC=golang-dev
https://golang.org/cl/6849045
2012-11-26 08:45:42 -07:00
|
|
|
addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneToString(int(sa.ZoneId))}
|
2012-09-24 15:57:32 -06:00
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2013-03-31 01:47:54 -06:00
|
|
|
// WriteToUDP writes a UDP packet to addr via c, copying the payload
|
|
|
|
// from b.
|
2011-08-17 11:28:29 -06:00
|
|
|
//
|
2013-03-31 01:47:54 -06:00
|
|
|
// WriteToUDP can be made to time out and return an error with
|
|
|
|
// Timeout() == true after a fixed time limit; see SetDeadline and
|
|
|
|
// SetWriteDeadline. On packet-oriented connections, write timeouts
|
|
|
|
// are rare.
|
2012-01-23 10:59:43 -07:00
|
|
|
func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error) {
|
2011-08-17 11:28:29 -06:00
|
|
|
if !c.ok() {
|
2012-02-16 16:04:29 -07:00
|
|
|
return 0, syscall.EINVAL
|
2011-08-17 11:28:29 -06:00
|
|
|
}
|
2012-01-26 09:31:42 -07:00
|
|
|
if c.fd.isConnected {
|
|
|
|
return 0, &OpError{"write", c.fd.net, addr, ErrWriteToConnected}
|
|
|
|
}
|
2012-01-23 10:59:43 -07:00
|
|
|
sa, err := addr.sockaddr(c.fd.family)
|
|
|
|
if err != nil {
|
|
|
|
return 0, &OpError{"write", c.fd.net, addr, err}
|
2011-08-17 11:28:29 -06:00
|
|
|
}
|
|
|
|
return c.fd.WriteTo(b, sa)
|
|
|
|
}
|
|
|
|
|
2012-01-29 03:11:05 -07:00
|
|
|
// WriteTo implements the PacketConn WriteTo method.
|
2012-01-23 10:59:43 -07:00
|
|
|
func (c *UDPConn) WriteTo(b []byte, addr Addr) (int, error) {
|
2011-08-17 11:28:29 -06:00
|
|
|
if !c.ok() {
|
2012-02-16 16:04:29 -07:00
|
|
|
return 0, syscall.EINVAL
|
2011-08-17 11:28:29 -06:00
|
|
|
}
|
|
|
|
a, ok := addr.(*UDPAddr)
|
|
|
|
if !ok {
|
2012-02-16 16:04:29 -07:00
|
|
|
return 0, &OpError{"write", c.fd.net, addr, syscall.EINVAL}
|
2011-08-17 11:28:29 -06:00
|
|
|
}
|
|
|
|
return c.WriteToUDP(b, a)
|
|
|
|
}
|
|
|
|
|
2012-09-24 15:57:32 -06:00
|
|
|
// WriteMsgUDP writes a packet to addr via c, copying the payload from
|
|
|
|
// b and the associated out-of-band data from oob. It returns the
|
|
|
|
// number of payload and out-of-band bytes written.
|
|
|
|
func (c *UDPConn) WriteMsgUDP(b, oob []byte, addr *UDPAddr) (n, oobn int, err error) {
|
|
|
|
if !c.ok() {
|
|
|
|
return 0, 0, syscall.EINVAL
|
|
|
|
}
|
|
|
|
if c.fd.isConnected {
|
|
|
|
return 0, 0, &OpError{"write", c.fd.net, addr, ErrWriteToConnected}
|
|
|
|
}
|
|
|
|
sa, err := addr.sockaddr(c.fd.family)
|
|
|
|
if err != nil {
|
|
|
|
return 0, 0, &OpError{"write", c.fd.net, addr, err}
|
|
|
|
}
|
|
|
|
return c.fd.WriteMsg(b, oob, sa)
|
|
|
|
}
|
|
|
|
|
2011-08-17 11:28:29 -06:00
|
|
|
// DialUDP connects to the remote address raddr on the network net,
|
2013-03-31 01:47:54 -06:00
|
|
|
// which must be "udp", "udp4", or "udp6". If laddr is not nil, it is
|
|
|
|
// used as the local address for the connection.
|
2012-01-31 08:36:45 -07:00
|
|
|
func DialUDP(net string, laddr, raddr *UDPAddr) (*UDPConn, error) {
|
2012-11-08 09:35:16 -07:00
|
|
|
return dialUDP(net, laddr, raddr, noDeadline)
|
|
|
|
}
|
|
|
|
|
|
|
|
func dialUDP(net string, laddr, raddr *UDPAddr, deadline time.Time) (*UDPConn, error) {
|
2011-08-17 11:28:29 -06:00
|
|
|
switch net {
|
|
|
|
case "udp", "udp4", "udp6":
|
|
|
|
default:
|
|
|
|
return nil, UnknownNetworkError(net)
|
|
|
|
}
|
|
|
|
if raddr == nil {
|
2012-01-23 10:59:43 -07:00
|
|
|
return nil, &OpError{"dial", net, nil, errMissingAddress}
|
2011-08-17 11:28:29 -06:00
|
|
|
}
|
2013-08-02 22:32:22 -06:00
|
|
|
fd, err := internetSocket(net, laddr, raddr, deadline, syscall.SOCK_DGRAM, 0, "dial", sockaddrToUDP)
|
2012-01-31 08:36:45 -07:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2011-08-17 11:28:29 -06:00
|
|
|
}
|
|
|
|
return newUDPConn(fd), nil
|
|
|
|
}
|
|
|
|
|
2013-03-29 00:06:43 -06:00
|
|
|
// ListenUDP listens for incoming UDP packets addressed to the local
|
|
|
|
// address laddr. Net must be "udp", "udp4", or "udp6". If laddr has
|
|
|
|
// a port of 0, ListenUDP will choose an available port.
|
|
|
|
// The LocalAddr method of the returned UDPConn can be used to
|
|
|
|
// discover the port. The returned connection's ReadFrom and WriteTo
|
|
|
|
// methods can be used to receive and send UDP packets with per-packet
|
|
|
|
// addressing.
|
2012-01-23 10:59:43 -07:00
|
|
|
func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error) {
|
2011-08-17 11:28:29 -06:00
|
|
|
switch net {
|
|
|
|
case "udp", "udp4", "udp6":
|
|
|
|
default:
|
|
|
|
return nil, UnknownNetworkError(net)
|
|
|
|
}
|
|
|
|
if laddr == nil {
|
2012-11-12 20:56:28 -07:00
|
|
|
laddr = &UDPAddr{}
|
2011-08-17 11:28:29 -06:00
|
|
|
}
|
2013-08-02 22:32:22 -06:00
|
|
|
fd, err := internetSocket(net, laddr, nil, noDeadline, syscall.SOCK_DGRAM, 0, "listen", sockaddrToUDP)
|
2012-01-23 10:59:43 -07:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2011-08-17 11:28:29 -06:00
|
|
|
}
|
|
|
|
return newUDPConn(fd), nil
|
|
|
|
}
|
|
|
|
|
2012-01-31 09:53:26 -07:00
|
|
|
// ListenMulticastUDP listens for incoming multicast UDP packets
|
2013-03-31 01:47:54 -06:00
|
|
|
// addressed to the group address gaddr on ifi, which specifies the
|
|
|
|
// interface to join. ListenMulticastUDP uses default multicast
|
|
|
|
// interface if ifi is nil.
|
2012-01-31 09:53:26 -07:00
|
|
|
func ListenMulticastUDP(net string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
|
|
|
|
switch net {
|
|
|
|
case "udp", "udp4", "udp6":
|
|
|
|
default:
|
|
|
|
return nil, UnknownNetworkError(net)
|
|
|
|
}
|
|
|
|
if gaddr == nil || gaddr.IP == nil {
|
2013-01-14 16:53:12 -07:00
|
|
|
return nil, &OpError{"listen", net, nil, errMissingAddress}
|
2012-01-31 09:53:26 -07:00
|
|
|
}
|
2013-08-02 22:32:22 -06:00
|
|
|
fd, err := internetSocket(net, gaddr, nil, noDeadline, syscall.SOCK_DGRAM, 0, "listen", sockaddrToUDP)
|
2012-01-31 09:53:26 -07:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
c := newUDPConn(fd)
|
2013-01-14 16:53:12 -07:00
|
|
|
if ip4 := gaddr.IP.To4(); ip4 != nil {
|
|
|
|
if err := listenIPv4MulticastUDP(c, ifi, ip4); err != nil {
|
2012-01-31 09:53:26 -07:00
|
|
|
c.Close()
|
2013-01-14 16:53:12 -07:00
|
|
|
return nil, &OpError{"listen", net, &IPAddr{IP: ip4}, err}
|
2012-01-31 09:53:26 -07:00
|
|
|
}
|
|
|
|
} else {
|
2013-01-14 16:53:12 -07:00
|
|
|
if err := listenIPv6MulticastUDP(c, ifi, gaddr.IP); err != nil {
|
2012-01-31 09:53:26 -07:00
|
|
|
c.Close()
|
2013-01-14 16:53:12 -07:00
|
|
|
return nil, &OpError{"listen", net, &IPAddr{IP: gaddr.IP}, err}
|
2012-01-31 09:53:26 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return c, nil
|
|
|
|
}
|
2011-08-17 11:28:29 -06:00
|
|
|
|
2012-01-31 09:53:26 -07:00
|
|
|
func listenIPv4MulticastUDP(c *UDPConn, ifi *Interface, ip IP) error {
|
|
|
|
if ifi != nil {
|
2013-01-14 16:53:12 -07:00
|
|
|
if err := setIPv4MulticastInterface(c.fd, ifi); err != nil {
|
2012-01-31 09:53:26 -07:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
2013-01-14 16:53:12 -07:00
|
|
|
if err := setIPv4MulticastLoopback(c.fd, false); err != nil {
|
2012-01-31 09:53:26 -07:00
|
|
|
return err
|
2011-08-18 10:22:02 -06:00
|
|
|
}
|
2013-01-14 16:53:12 -07:00
|
|
|
if err := joinIPv4Group(c.fd, ifi, ip); err != nil {
|
2012-01-31 09:53:26 -07:00
|
|
|
return err
|
2011-08-18 10:22:02 -06:00
|
|
|
}
|
2012-01-31 09:53:26 -07:00
|
|
|
return nil
|
2011-08-18 10:22:02 -06:00
|
|
|
}
|
2011-08-17 11:28:29 -06:00
|
|
|
|
2012-01-31 09:53:26 -07:00
|
|
|
func listenIPv6MulticastUDP(c *UDPConn, ifi *Interface, ip IP) error {
|
|
|
|
if ifi != nil {
|
2013-01-14 16:53:12 -07:00
|
|
|
if err := setIPv6MulticastInterface(c.fd, ifi); err != nil {
|
2012-01-31 09:53:26 -07:00
|
|
|
return err
|
|
|
|
}
|
2011-08-17 11:28:29 -06:00
|
|
|
}
|
2013-01-14 16:53:12 -07:00
|
|
|
if err := setIPv6MulticastLoopback(c.fd, false); err != nil {
|
2012-01-31 09:53:26 -07:00
|
|
|
return err
|
2011-08-17 11:28:29 -06:00
|
|
|
}
|
2013-01-14 16:53:12 -07:00
|
|
|
if err := joinIPv6Group(c.fd, ifi, ip); err != nil {
|
2012-01-31 09:53:26 -07:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
2011-08-18 10:22:02 -06:00
|
|
|
}
|