net: several family detection fixes for fuchsia
This gets us a few more unit tests into the Go net package.
Some of this logic comes from the _posix.go files.
Change-Id: I9e8b8af19d83eb0a9ba547c09d4c48d8608f2fea
diff --git a/src/net/ipsock_fuchsia.go b/src/net/ipsock_fuchsia.go
index ccc9206..c26e7fe 100644
--- a/src/net/ipsock_fuchsia.go
+++ b/src/net/ipsock_fuchsia.go
@@ -19,7 +19,7 @@
}
func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
- return true, false
+ return true, true
}
// A sockaddr represents a TCP, UDP, IP or Unix network endpoint
@@ -27,21 +27,45 @@
type sockaddr interface {
Addr
- sockaddr() (addr string, port uint16)
+ family() int
+ isWildcard() bool
+ sockaddr(family int) (addr mxnet.Addr, port uint16, err error)
+}
+
+func favoriteAddrFamily(net string, laddr, raddr sockaddr, mode string) (family int, ipv6only bool) {
+ switch net[len(net)-1] {
+ case '4':
+ return syscall.AF_INET, false
+ case '6':
+ return syscall.AF_INET6, true
+ }
+
+ if mode == "listen" && (laddr == nil || laddr.isWildcard()) {
+ if supportsIPv4map || !supportsIPv4 {
+ return syscall.AF_INET6, false
+ }
+ if laddr == nil {
+ return syscall.AF_INET, false
+ }
+ return laddr.family(), false
+ }
+
+ if (laddr == nil || laddr.family() == syscall.AF_INET) &&
+ (raddr == nil || raddr.family() == syscall.AF_INET) {
+ return syscall.AF_INET, false
+ }
+ return syscall.AF_INET6, false
}
func dialFuchsia(ctx context.Context, net string, laddr, raddr sockaddr) (fd *netFD, err error) {
- domain := syscall.AF_INET6
- if net[len(net)-1] == '4' {
- domain = syscall.AF_INET
- }
+ family, _ := favoriteAddrFamily(net, laddr, raddr, "dial")
sotype := syscall.SOCK_STREAM
if len(net) >= 3 && net[:3] == "udp" {
sotype = syscall.SOCK_DGRAM
}
proto := syscall.IPPROTO_IP
- path := "/dev/socket/socket/" + strconv.Itoa(domain) + "/" + strconv.Itoa(sotype) + "/" + strconv.Itoa(proto)
+ path := "/dev/socket/socket/" + strconv.Itoa(family) + "/" + strconv.Itoa(sotype) + "/" + strconv.Itoa(proto)
f, err := os.Open(path)
if err != nil {
return nil, err
@@ -54,15 +78,20 @@
fd = &netFD{
hsrc: f,
m: m,
- family: domain,
+ family: family,
sotype: sotype,
net: net,
}
if laddr != nil {
- addr, port := laddr.sockaddr()
- if err := rio.Bind(fd.m, mxnet.Addr(addr), port); err != nil {
+ addr, port, err := laddr.sockaddr(family)
+ if err != nil {
return nil, err
}
+ if addr != "" || port != 0 {
+ if err := rio.Bind(fd.m, addr, port); err != nil {
+ return nil, err
+ }
+ }
if raddr == nil {
switch sotype {
case syscall.SOCK_STREAM:
@@ -75,8 +104,11 @@
}
}
if raddr != nil {
- addr, port := raddr.sockaddr()
- if err := rio.Connect(fd.m, mxnet.Addr(addr), port); err != nil {
+ addr, port, err := raddr.sockaddr(family)
+ if err != nil {
+ return nil, err
+ }
+ if err := rio.Connect(fd.m, addr, port); err != nil {
return nil, err
}
fd.isConnected = true
@@ -85,3 +117,27 @@
return fd, nil
}
+
+func ipToSockaddr(family int, ip IP, port int, zone string) (addr mxnet.Addr, portres uint16, err error) {
+ switch family {
+ case syscall.AF_INET:
+ if len(ip) == 0 {
+ ip = IPv4zero
+ }
+ ip4 := ip.To4()
+ if ip4 == nil {
+ return "", 0, &AddrError{Err: "non-IPv4 address", Addr: ip.String()}
+ }
+ return mxnet.Addr(ip4)[:4], uint16(port), nil
+ case syscall.AF_INET6:
+ if len(ip) == 0 || ip.Equal(IPv4zero) {
+ ip = IPv6zero
+ }
+ ip6 := ip.To16()
+ if ip6 == nil {
+ return "", 0, &AddrError{Err: "non-IPv6 address", Addr: ip.String()}
+ }
+ return mxnet.Addr(ip6), uint16(port), nil
+ }
+ return "", 0, &AddrError{Err: "invalid address family", Addr: ip.String()}
+}
diff --git a/src/net/platform_test.go b/src/net/platform_test.go
index 2a14095..cc03c81 100644
--- a/src/net/platform_test.go
+++ b/src/net/platform_test.go
@@ -33,7 +33,7 @@
}
case "unix", "unixgram":
switch runtime.GOOS {
- case "android", "nacl", "plan9", "windows":
+ case "android", "fuchsia", "nacl", "plan9", "windows":
return false
}
// iOS does not support unix, unixgram.
@@ -42,7 +42,7 @@
}
case "unixpacket":
switch runtime.GOOS {
- case "android", "darwin", "nacl", "plan9", "windows":
+ case "android", "darwin", "fuchsia", "nacl", "plan9", "windows":
fallthrough
case "freebsd": // FreeBSD 8 and below don't support unixpacket
return false
diff --git a/src/net/tcpsock_fuchsia.go b/src/net/tcpsock_fuchsia.go
index aa4103b..66405d4 100644
--- a/src/net/tcpsock_fuchsia.go
+++ b/src/net/tcpsock_fuchsia.go
@@ -28,11 +28,11 @@
return syscall.AF_INET6
}
-func (a *TCPAddr) sockaddr() (addr string, port uint16) {
+func (a *TCPAddr) sockaddr(family int) (addr mxnet.Addr, port uint16, err error) {
if a == nil {
- return "", 0
+ return "", 0, nil
}
- return string(a.IP), uint16(a.Port)
+ return ipToSockaddr(family, a.IP, a.Port, a.Zone)
}
func (c *TCPConn) readFrom(r io.Reader) (int64, error) {
diff --git a/src/net/udpsock_fuchsia.go b/src/net/udpsock_fuchsia.go
index 5d59198..b11d952 100644
--- a/src/net/udpsock_fuchsia.go
+++ b/src/net/udpsock_fuchsia.go
@@ -26,11 +26,11 @@
return syscall.AF_INET6
}
-func (a *UDPAddr) sockaddr() (addr string, port uint16) {
+func (a *UDPAddr) sockaddr(family int) (addr mxnet.Addr, port uint16, err error) {
if a == nil {
- return "", 0
+ return "", 0, nil
}
- return string(a.IP), uint16(a.Port)
+ return ipToSockaddr(family, a.IP, a.Port, a.Zone)
}
func (c *UDPConn) readFrom(b []byte) (n int, addr *UDPAddr, err error) {
diff --git a/src/syscall/mx/mxio/rio/socket.go b/src/syscall/mx/mxio/rio/socket.go
index 9c192d0..11d334c 100644
--- a/src/syscall/mx/mxio/rio/socket.go
+++ b/src/syscall/mx/mxio/rio/socket.go
@@ -211,10 +211,11 @@
return errors.New("rio.Bind: nil argument")
}
b := make([]byte, mxnet.SockaddrLen)
- _, err := mxnet.EncodeSockaddr(b, addr, port)
+ addrlen, err := mxnet.EncodeSockaddr(b, addr, port)
if err != nil {
return err
}
+ b = b[:addrlen]
s, ok := m.(*Socket)
if !ok {
@@ -230,10 +231,11 @@
return errors.New("rio.Connect: nil argument")
}
b := make([]byte, mxnet.SockaddrLen)
- _, err := mxnet.EncodeSockaddr(b, addr, port)
+ addrlen, err := mxnet.EncodeSockaddr(b, addr, port)
if err != nil {
return err
}
+ b = b[:addrlen]
s, ok := m.(*Socket)
if !ok {