return "", 0, UnknownNetworkError(net)
}
-func resolveAddr(op, net, addr string, deadline time.Time) (netaddr, error) {
+func resolveAddrList(op, net, addr string, deadline time.Time) (addrList, error) {
afnet, _, err := parseNetwork(net)
if err != nil {
return nil, err
}
switch afnet {
case "unix", "unixgram", "unixpacket":
- return ResolveUnixAddr(afnet, addr)
+ addr, err := ResolveUnixAddr(afnet, addr)
+ if err != nil {
+ return nil, err
+ }
+ return addrList{addr}, nil
}
- return resolveInternetAddr(afnet, addr, deadline)
+ return internetAddrList(afnet, addr, deadline)
}
// Dial connects to the address on the named network.
// See func Dial for a description of the network and address
// parameters.
func (d *Dialer) Dial(network, address string) (Conn, error) {
- ra, err := resolveAddr("dial", network, address, d.deadline())
+ addrs, err := resolveAddrList("dial", network, address, d.deadline())
if err != nil {
return nil, &OpError{Op: "dial", Net: network, Addr: nil, Err: err}
}
var dialer func(deadline time.Time) (Conn, error)
- if ras, ok := ra.(addrList); ok && d.DualStack && network == "tcp" {
- dialer = func(deadline time.Time) (Conn, error) {
- return dialMulti(network, address, d.LocalAddr, ras, deadline)
+ if d.DualStack && network == "tcp" {
+ primaries, fallbacks := addrs.partition(isIPv4)
+ if len(fallbacks) > 0 {
+ dialer = func(deadline time.Time) (Conn, error) {
+ return dialMulti(network, address, d.LocalAddr, addrList{primaries[0], fallbacks[0]}, deadline)
+ }
}
- } else {
+ }
+ if dialer == nil {
dialer = func(deadline time.Time) (Conn, error) {
- return dialSingle(network, address, d.LocalAddr, ra.toAddr(), deadline)
+ return dialSingle(network, address, d.LocalAddr, addrs.first(isIPv4), deadline)
}
}
- c, err := dial(network, ra.toAddr(), dialer, d.deadline())
+ c, err := dial(network, addrs.first(isIPv4), dialer, d.deadline())
if d.KeepAlive > 0 && err == nil {
if tc, ok := c.(*TCPConn); ok {
tc.SetKeepAlive(true)
// unnecessary resource starvation.
c.Close()
}
- }(ra.toAddr())
+ }(ra)
}
defer close(sig)
lastErr := errTimeout
// "tcp6", "unix" or "unixpacket".
// See Dial for the syntax of laddr.
func Listen(net, laddr string) (Listener, error) {
- la, err := resolveAddr("listen", net, laddr, noDeadline)
+ addrs, err := resolveAddrList("listen", net, laddr, noDeadline)
if err != nil {
return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: err}
}
var l Listener
- switch la := la.toAddr().(type) {
+ switch la := addrs.first(isIPv4).(type) {
case *TCPAddr:
l, err = ListenTCP(net, la)
case *UnixAddr:
// "udp6", "ip", "ip4", "ip6" or "unixgram".
// See Dial for the syntax of laddr.
func ListenPacket(net, laddr string) (PacketConn, error) {
- la, err := resolveAddr("listen", net, laddr, noDeadline)
+ addrs, err := resolveAddrList("listen", net, laddr, noDeadline)
if err != nil {
return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: err}
}
var l PacketConn
- switch la := la.toAddr().(type) {
+ switch la := addrs.first(isIPv4).(type) {
case *UDPAddr:
l, err = ListenUDP(net, la)
case *IPAddr:
b[i/2], _ = xtoi2(f[0][i:i+2], 0)
}
i := *(*uint32)(unsafe.Pointer(&b[:4][0]))
- ifma := IPAddr{IP: IPv4(byte(i>>24), byte(i>>16), byte(i>>8), byte(i))}
- ifmat = append(ifmat, ifma.toAddr())
+ ifma := &IPAddr{IP: IPv4(byte(i>>24), byte(i>>16), byte(i>>8), byte(i))}
+ ifmat = append(ifmat, ifma)
}
}
}
for i := 0; i+1 < len(f[2]); i += 2 {
b[i/2], _ = xtoi2(f[2][i:i+2], 0)
}
- ifma := IPAddr{IP: IP{b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]}}
- ifmat = append(ifmat, ifma.toAddr())
+ ifma := &IPAddr{IP: IP{b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]}}
+ ifmat = append(ifmat, ifma)
}
}
return ifmat
case *syscall.SockaddrInet4:
ifa := &IPAddr{IP: make(IP, IPv4len)}
copy(ifa.IP, sav.Addr[:])
- ifat = append(ifat, ifa.toAddr())
+ ifat = append(ifat, ifa)
case *syscall.SockaddrInet6:
ifa := &IPAddr{IP: make(IP, IPv6len)}
copy(ifa.IP, sav.Addr[:])
- ifat = append(ifat, ifa.toAddr())
+ ifat = append(ifat, ifa)
}
}
}
return a.IP.IsUnspecified()
}
-func (a *IPAddr) toAddr() Addr {
- if a == nil {
- return nil
- }
- return a
-}
-
// ResolveIPAddr parses addr as an IP address of the form "host" or
// "ipv6-host%zone" and resolves the domain name on the network net,
// which must be "ip", "ip4" or "ip6".
default:
return nil, UnknownNetworkError(net)
}
- a, err := resolveInternetAddr(afnet, addr, noDeadline)
+ addrs, err := internetAddrList(afnet, addr, noDeadline)
if err != nil {
return nil, err
}
- return a.toAddr().(*IPAddr), nil
+ return addrs.first(isIPv4).(*IPAddr), nil
}
return 0, nil, syscall.EINVAL
}
n, addr, err := c.ReadFromIP(b)
- return n, addr.toAddr(), err
+ if addr == nil {
+ return n, nil, err
+ }
+ return n, addr, err
}
// ReadMsgIP reads a packet from c, copying the payload into b and the
supportsIPv4map bool
)
-// A netaddr represents a network endpoint address or a list of
-// network endpoint addresses.
-type netaddr interface {
- // toAddr returns the address represented in Addr interface.
- // It returns a nil interface when the address is nil.
- toAddr() Addr
-}
-
// An addrList represents a list of network endpoint addresses.
-type addrList []netaddr
+type addrList []Addr
-func (al addrList) toAddr() Addr {
- switch len(al) {
- case 0:
- return nil
- case 1:
- return al[0].toAddr()
- default:
- // For now, we'll roughly pick first one without
- // considering dealing with any preferences such as
- // DNS TTL, transport path quality, network routing
- // information.
- return al[0].toAddr()
+// isIPv4 returns true if the Addr contains an IPv4 address.
+func isIPv4(addr Addr) bool {
+ switch addr := addr.(type) {
+ case *TCPAddr:
+ return addr.IP.To4() != nil
+ case *UDPAddr:
+ return addr.IP.To4() != nil
+ case *IPAddr:
+ return addr.IP.To4() != nil
}
+ return false
}
-var errNoSuitableAddress = errors.New("no suitable address found")
-
-// firstFavoriteAddr returns an address or a list of addresses that
-// implement the netaddr interface. Known filters are nil, ipv4only
-// and ipv6only. It returns any address when filter is nil. The result
-// contains at least one address when error is nil.
-func firstFavoriteAddr(filter func(IPAddr) bool, ips []IPAddr, inetaddr func(IPAddr) netaddr) (netaddr, error) {
- if filter != nil {
- return firstSupportedAddr(filter, ips, inetaddr)
- }
- var (
- ipv4, ipv6, swap bool
- list addrList
- )
- for _, ip := range ips {
- // We'll take any IP address, but since the dialing
- // code does not yet try multiple addresses
- // effectively, prefer to use an IPv4 address if
- // possible. This is especially relevant if localhost
- // resolves to [ipv6-localhost, ipv4-localhost]. Too
- // much code assumes localhost == ipv4-localhost.
- if ipv4only(ip) && !ipv4 {
- list = append(list, inetaddr(ip))
- ipv4 = true
- if ipv6 {
- swap = true
- }
- } else if ipv6only(ip) && !ipv6 {
- list = append(list, inetaddr(ip))
- ipv6 = true
- }
- if ipv4 && ipv6 {
- if swap {
- list[0], list[1] = list[1], list[0]
- }
- break
+// first returns the first address which satisfies strategy, or if
+// none do, then the first address of any kind.
+func (addrs addrList) first(strategy func(Addr) bool) Addr {
+ for _, addr := range addrs {
+ if strategy(addr) {
+ return addr
}
}
- switch len(list) {
- case 0:
- return nil, errNoSuitableAddress
- case 1:
- return list[0], nil
- default:
- return list, nil
+ return addrs[0]
+}
+
+// partition divides an address list into two categories, using a
+// strategy function to assign a boolean label to each address.
+// The first address, and any with a matching label, are returned as
+// primaries, while addresses with the opposite label are returned
+// as fallbacks. For non-empty inputs, primaries is guaranteed to be
+// non-empty.
+func (addrs addrList) partition(strategy func(Addr) bool) (primaries, fallbacks addrList) {
+ var primaryLabel bool
+ for i, addr := range addrs {
+ label := strategy(addr)
+ if i == 0 || label == primaryLabel {
+ primaryLabel = label
+ primaries = append(primaries, addr)
+ } else {
+ fallbacks = append(fallbacks, addr)
+ }
}
+ return
}
-func firstSupportedAddr(filter func(IPAddr) bool, ips []IPAddr, inetaddr func(IPAddr) netaddr) (netaddr, error) {
+var errNoSuitableAddress = errors.New("no suitable address found")
+
+// filterAddrList applies a filter to a list of IP addresses,
+// yielding a list of Addr objects. Known filters are nil, ipv4only,
+// and ipv6only. It returns every address when the filter is nil.
+// The result contains at least one address when error is nil.
+func filterAddrList(filter func(IPAddr) bool, ips []IPAddr, inetaddr func(IPAddr) Addr) (addrList, error) {
+ var addrs addrList
for _, ip := range ips {
- if filter(ip) {
- return inetaddr(ip), nil
+ if filter == nil || filter(ip) {
+ addrs = append(addrs, inetaddr(ip))
}
}
- return nil, errNoSuitableAddress
+ if len(addrs) == 0 {
+ return nil, errNoSuitableAddress
+ }
+ return addrs, nil
}
// ipv4only reports whether the kernel supports IPv4 addressing mode
return host + ":" + port
}
-// resolveInternetAddr resolves addr that is either a literal IP
-// address or a DNS name and returns an internet protocol family
-// address. It returns a list that contains a pair of different
-// address family addresses when addr is a DNS name and the name has
-// multiple address family records. The result contains at least one
-// address when error is nil.
-func resolveInternetAddr(net, addr string, deadline time.Time) (netaddr, error) {
+// internetAddrList resolves addr, which may be a literal IP
+// address or a DNS name, and returns a list of internet protocol
+// family addresses. The result contains at least one address when
+// error is nil.
+func internetAddrList(net, addr string, deadline time.Time) (addrList, error) {
var (
err error
host, port string
default:
return nil, UnknownNetworkError(net)
}
- inetaddr := func(ip IPAddr) netaddr {
+ inetaddr := func(ip IPAddr) Addr {
switch net {
case "tcp", "tcp4", "tcp6":
return &TCPAddr{IP: ip.IP, Port: portnum, Zone: ip.Zone}
}
}
if host == "" {
- return inetaddr(IPAddr{}), nil
+ return addrList{inetaddr(IPAddr{})}, nil
}
// Try as a literal IP address.
var ip IP
if ip = parseIPv4(host); ip != nil {
- return inetaddr(IPAddr{IP: ip}), nil
+ return addrList{inetaddr(IPAddr{IP: ip})}, nil
}
var zone string
if ip, zone = parseIPv6(host, true); ip != nil {
- return inetaddr(IPAddr{IP: ip, Zone: zone}), nil
+ return addrList{inetaddr(IPAddr{IP: ip, Zone: zone})}, nil
}
// Try as a DNS name.
ips, err := lookupIPDeadline(host, deadline)
if net != "" && net[len(net)-1] == '6' {
filter = ipv6only
}
- return firstFavoriteAddr(filter, ips, inetaddr)
+ return filterAddrList(filter, ips, inetaddr)
}
func zoneToString(zone int) string {
"testing"
)
-var testInetaddr = func(ip IPAddr) netaddr { return &TCPAddr{IP: ip.IP, Port: 5682, Zone: ip.Zone} }
+var testInetaddr = func(ip IPAddr) Addr { return &TCPAddr{IP: ip.IP, Port: 5682, Zone: ip.Zone} }
-var firstFavoriteAddrTests = []struct {
- filter func(IPAddr) bool
- ips []IPAddr
- inetaddr func(IPAddr) netaddr
- addr netaddr
- err error
+var addrListTests = []struct {
+ filter func(IPAddr) bool
+ ips []IPAddr
+ inetaddr func(IPAddr) Addr
+ first Addr
+ primaries addrList
+ fallbacks addrList
+ err error
}{
{
nil,
{IP: IPv6loopback},
},
testInetaddr,
- addrList{
- &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
- &TCPAddr{IP: IPv6loopback, Port: 5682},
- },
+ &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
+ addrList{&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}},
+ addrList{&TCPAddr{IP: IPv6loopback, Port: 5682}},
nil,
},
{
{IP: IPv4(127, 0, 0, 1)},
},
testInetaddr,
- addrList{
- &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
- &TCPAddr{IP: IPv6loopback, Port: 5682},
- },
+ &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
+ addrList{&TCPAddr{IP: IPv6loopback, Port: 5682}},
+ addrList{&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}},
nil,
},
{
},
testInetaddr,
&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
+ addrList{
+ &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
+ &TCPAddr{IP: IPv4(192, 168, 0, 1), Port: 5682},
+ },
+ nil,
nil,
},
{
},
testInetaddr,
&TCPAddr{IP: IPv6loopback, Port: 5682},
+ addrList{
+ &TCPAddr{IP: IPv6loopback, Port: 5682},
+ &TCPAddr{IP: ParseIP("fe80::1"), Port: 5682, Zone: "eth0"},
+ },
+ nil,
nil,
},
{
{IP: ParseIP("fe80::1"), Zone: "eth0"},
},
testInetaddr,
+ &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
addrList{
&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
+ &TCPAddr{IP: IPv4(192, 168, 0, 1), Port: 5682},
+ },
+ addrList{
&TCPAddr{IP: IPv6loopback, Port: 5682},
+ &TCPAddr{IP: ParseIP("fe80::1"), Port: 5682, Zone: "eth0"},
},
nil,
},
{IP: IPv4(192, 168, 0, 1)},
},
testInetaddr,
+ &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
addrList{
- &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
&TCPAddr{IP: IPv6loopback, Port: 5682},
+ &TCPAddr{IP: ParseIP("fe80::1"), Port: 5682, Zone: "eth0"},
+ },
+ addrList{
+ &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
+ &TCPAddr{IP: IPv4(192, 168, 0, 1), Port: 5682},
},
nil,
},
{IP: ParseIP("fe80::1"), Zone: "eth0"},
},
testInetaddr,
+ &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
addrList{
&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
+ &TCPAddr{IP: IPv4(192, 168, 0, 1), Port: 5682},
+ },
+ addrList{
&TCPAddr{IP: IPv6loopback, Port: 5682},
+ &TCPAddr{IP: ParseIP("fe80::1"), Port: 5682, Zone: "eth0"},
},
nil,
},
{IP: IPv4(192, 168, 0, 1)},
},
testInetaddr,
+ &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
addrList{
- &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
&TCPAddr{IP: IPv6loopback, Port: 5682},
+ &TCPAddr{IP: ParseIP("fe80::1"), Port: 5682, Zone: "eth0"},
+ },
+ addrList{
+ &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
+ &TCPAddr{IP: IPv4(192, 168, 0, 1), Port: 5682},
},
nil,
},
},
testInetaddr,
&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
+ addrList{&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}},
+ nil,
nil,
},
{
},
testInetaddr,
&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
+ addrList{&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}},
+ nil,
nil,
},
},
testInetaddr,
&TCPAddr{IP: IPv6loopback, Port: 5682},
+ addrList{&TCPAddr{IP: IPv6loopback, Port: 5682}},
+ nil,
nil,
},
{
},
testInetaddr,
&TCPAddr{IP: IPv6loopback, Port: 5682},
+ addrList{&TCPAddr{IP: IPv6loopback, Port: 5682}},
+ nil,
nil,
},
- {nil, nil, testInetaddr, nil, errNoSuitableAddress},
+ {nil, nil, testInetaddr, nil, nil, nil, errNoSuitableAddress},
- {ipv4only, nil, testInetaddr, nil, errNoSuitableAddress},
- {ipv4only, []IPAddr{{IP: IPv6loopback}}, testInetaddr, nil, errNoSuitableAddress},
+ {ipv4only, nil, testInetaddr, nil, nil, nil, errNoSuitableAddress},
+ {ipv4only, []IPAddr{{IP: IPv6loopback}}, testInetaddr, nil, nil, nil, errNoSuitableAddress},
- {ipv6only, nil, testInetaddr, nil, errNoSuitableAddress},
- {ipv6only, []IPAddr{{IP: IPv4(127, 0, 0, 1)}}, testInetaddr, nil, errNoSuitableAddress},
+ {ipv6only, nil, testInetaddr, nil, nil, nil, errNoSuitableAddress},
+ {ipv6only, []IPAddr{{IP: IPv4(127, 0, 0, 1)}}, testInetaddr, nil, nil, nil, errNoSuitableAddress},
}
-func TestFirstFavoriteAddr(t *testing.T) {
+func TestAddrList(t *testing.T) {
if !supportsIPv4 || !supportsIPv6 {
t.Skip("ipv4 or ipv6 is not supported")
}
- for i, tt := range firstFavoriteAddrTests {
- addr, err := firstFavoriteAddr(tt.filter, tt.ips, tt.inetaddr)
+ for i, tt := range addrListTests {
+ addrs, err := filterAddrList(tt.filter, tt.ips, tt.inetaddr)
if err != tt.err {
- t.Errorf("#%v: got %v; expected %v", i, err, tt.err)
+ t.Errorf("#%v: got %v; want %v", i, err, tt.err)
+ }
+ if tt.err != nil {
+ if len(addrs) != 0 {
+ t.Errorf("#%v: got %v; want 0", len(addrs))
+ }
+ continue
+ }
+ first := addrs.first(isIPv4)
+ if !reflect.DeepEqual(first, tt.first) {
+ t.Errorf("#%v: got %v; want %v", i, first, tt.first)
+ }
+ primaries, fallbacks := addrs.partition(isIPv4)
+ if !reflect.DeepEqual(primaries, tt.primaries) {
+ t.Errorf("#%v: got %v; want %v", i, primaries, tt.primaries)
+ }
+ if !reflect.DeepEqual(fallbacks, tt.fallbacks) {
+ t.Errorf("#%v: got %v; want %v", i, fallbacks, tt.fallbacks)
}
- if !reflect.DeepEqual(addr, tt.addr) {
- t.Errorf("#%v: got %v; expected %v", i, addr, tt.addr)
+ expectedLen := len(primaries) + len(fallbacks)
+ if len(addrs) != expectedLen {
+ t.Errorf("#%v: got %v; want %v", i, len(addrs), expectedLen)
+ }
+ }
+}
+
+func TestAddrListPartition(t *testing.T) {
+ addrs := addrList{
+ &IPAddr{IP: ParseIP("fe80::"), Zone: "eth0"},
+ &IPAddr{IP: ParseIP("fe80::1"), Zone: "eth0"},
+ &IPAddr{IP: ParseIP("fe80::2"), Zone: "eth0"},
+ }
+ cases := []struct {
+ lastByte byte
+ primaries addrList
+ fallbacks addrList
+ }{
+ {0, addrList{addrs[0]}, addrList{addrs[1], addrs[2]}},
+ {1, addrList{addrs[0], addrs[2]}, addrList{addrs[1]}},
+ {2, addrList{addrs[0], addrs[1]}, addrList{addrs[2]}},
+ {3, addrList{addrs[0], addrs[1], addrs[2]}, nil},
+ }
+ for i, tt := range cases {
+ // Inverting the function's output should not affect the outcome.
+ for _, invert := range []bool{false, true} {
+ primaries, fallbacks := addrs.partition(func(a Addr) bool {
+ ip := a.(*IPAddr).IP
+ return (ip[len(ip)-1] == tt.lastByte) != invert
+ })
+ if !reflect.DeepEqual(primaries, tt.primaries) {
+ t.Errorf("#%v: got %v; want %v", i, primaries, tt.primaries)
+ }
+ if !reflect.DeepEqual(fallbacks, tt.fallbacks) {
+ t.Errorf("#%v: got %v; want %v", i, fallbacks, tt.fallbacks)
+ }
}
}
}
type sockaddr interface {
Addr
- netaddr
-
// family returns the platform-dependent address family
// identifier.
family() int
return a.IP.IsUnspecified()
}
-func (a *TCPAddr) toAddr() Addr {
- if a == nil {
- return nil
- }
- return a
-}
-
// ResolveTCPAddr parses addr as a TCP address of the form "host:port"
// or "[ipv6-host%zone]:port" and resolves a pair of domain name and
// port name on the network net, which must be "tcp", "tcp4" or
default:
return nil, UnknownNetworkError(net)
}
- a, err := resolveInternetAddr(net, addr, noDeadline)
+ addrs, err := internetAddrList(net, addr, noDeadline)
if err != nil {
return nil, err
}
- return a.toAddr().(*TCPAddr), nil
+ return addrs.first(isIPv4).(*TCPAddr), nil
}
return a.IP.IsUnspecified()
}
-func (a *UDPAddr) toAddr() Addr {
- if a == nil {
- return nil
- }
- return a
-}
-
// ResolveUDPAddr parses addr as a UDP address of the form "host:port"
// or "[ipv6-host%zone]:port" and resolves a pair of domain name and
// port name on the network net, which must be "udp", "udp4" or
default:
return nil, UnknownNetworkError(net)
}
- a, err := resolveInternetAddr(net, addr, noDeadline)
+ addrs, err := internetAddrList(net, addr, noDeadline)
if err != nil {
return nil, err
}
- return a.toAddr().(*UDPAddr), nil
+ return addrs.first(isIPv4).(*UDPAddr), nil
}
return 0, nil, syscall.EINVAL
}
n, addr, err := c.ReadFromUDP(b)
- return n, addr.toAddr(), err
+ if addr == nil {
+ return n, nil, err
+ }
+ return n, addr, err
}
// ReadMsgUDP reads a packet from c, copying the payload into b and
return a.Name
}
-func (a *UnixAddr) toAddr() Addr {
- if a == nil {
- return nil
- }
- return a
-}
-
// ResolveUnixAddr parses addr as a Unix domain socket address.
// The string net gives the network name, "unix", "unixgram" or
// "unixpacket".
return 0, nil, syscall.EINVAL
}
n, addr, err := c.ReadFromUnix(b)
- return n, addr.toAddr(), err
+ if addr == nil {
+ return n, nil, err
+ }
+ return n, addr, err
}
// ReadMsgUnix reads a packet from c, copying the payload into b and