Commit 8a7def2b authored by Mikio Hara's avatar Mikio Hara

net: reduce unnecessary syscall.Sockaddr conversions

This CL makes IPAddr, UDPAddr and TCPAddr implement sockaddr
interface, UnixAddr is already sockaddr interface compliant, and
reduces unnecessary conversions between net.Addr, net.sockaddr and
syscall.Sockaddr.

This is in preparation for runtime-integrated network pollster for BSD
variants.

Update #5199

R=golang-dev, dave, bradfitz
CC=golang-dev
https://golang.org/cl/12010043
parent f0291a8e
...@@ -39,12 +39,15 @@ func (a *IPAddr) isWildcard() bool { ...@@ -39,12 +39,15 @@ func (a *IPAddr) isWildcard() bool {
} }
func (a *IPAddr) sockaddr(family int) (syscall.Sockaddr, error) { func (a *IPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
if a == nil {
return nil, nil
}
return ipToSockaddr(family, a.IP, 0, a.Zone) return ipToSockaddr(family, a.IP, 0, a.Zone)
} }
func (a *IPAddr) toAddr() sockaddr { func (a *IPAddr) toAddr() sockaddr {
if a == nil { // nil *IPAddr if a == nil {
return nil // nil interface return nil
} }
return a return a
} }
...@@ -178,7 +181,7 @@ func dialIP(netProto string, laddr, raddr *IPAddr, deadline time.Time) (*IPConn, ...@@ -178,7 +181,7 @@ func dialIP(netProto string, laddr, raddr *IPAddr, deadline time.Time) (*IPConn,
if raddr == nil { if raddr == nil {
return nil, &OpError{"dial", netProto, nil, errMissingAddress} return nil, &OpError{"dial", netProto, nil, errMissingAddress}
} }
fd, err := internetSocket(net, laddr.toAddr(), raddr.toAddr(), deadline, syscall.SOCK_RAW, proto, "dial", sockaddrToIP) fd, err := internetSocket(net, laddr, raddr, deadline, syscall.SOCK_RAW, proto, "dial", sockaddrToIP)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -199,7 +202,7 @@ func ListenIP(netProto string, laddr *IPAddr) (*IPConn, error) { ...@@ -199,7 +202,7 @@ func ListenIP(netProto string, laddr *IPAddr) (*IPConn, error) {
default: default:
return nil, UnknownNetworkError(netProto) return nil, UnknownNetworkError(netProto)
} }
fd, err := internetSocket(net, laddr.toAddr(), nil, noDeadline, syscall.SOCK_RAW, proto, "listen", sockaddrToIP) fd, err := internetSocket(net, laddr, nil, noDeadline, syscall.SOCK_RAW, proto, "listen", sockaddrToIP)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
...@@ -132,19 +132,8 @@ func favoriteAddrFamily(net string, laddr, raddr sockaddr, mode string) (family ...@@ -132,19 +132,8 @@ func favoriteAddrFamily(net string, laddr, raddr sockaddr, mode string) (family
// Internet sockets (TCP, UDP, IP) // Internet sockets (TCP, UDP, IP)
func internetSocket(net string, laddr, raddr sockaddr, deadline time.Time, sotype, proto int, mode string, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err error) { func internetSocket(net string, laddr, raddr sockaddr, deadline time.Time, sotype, proto int, mode string, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err error) {
var la, ra syscall.Sockaddr
family, ipv6only := favoriteAddrFamily(net, laddr, raddr, mode) family, ipv6only := favoriteAddrFamily(net, laddr, raddr, mode)
if laddr != nil { fd, err = socket(net, family, sotype, proto, ipv6only, laddr, raddr, deadline, toAddr)
if la, err = laddr.sockaddr(family); err != nil {
goto Error
}
}
if raddr != nil {
if ra, err = raddr.sockaddr(family); err != nil {
goto Error
}
}
fd, err = socket(net, family, sotype, proto, ipv6only, la, ra, deadline, toAddr)
if err != nil { if err != nil {
goto Error goto Error
} }
......
...@@ -37,7 +37,7 @@ type sockaddr interface { ...@@ -37,7 +37,7 @@ type sockaddr interface {
} }
// Generic POSIX socket creation. // Generic POSIX socket creation.
func socket(net string, f, t, p int, ipv6only bool, ulsa, ursa syscall.Sockaddr, deadline time.Time, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err error) { func socket(net string, f, t, p int, ipv6only bool, laddr, raddr sockaddr, deadline time.Time, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err error) {
s, err := sysSocket(f, t, p) s, err := sysSocket(f, t, p)
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -48,23 +48,42 @@ func socket(net string, f, t, p int, ipv6only bool, ulsa, ursa syscall.Sockaddr, ...@@ -48,23 +48,42 @@ func socket(net string, f, t, p int, ipv6only bool, ulsa, ursa syscall.Sockaddr,
return nil, err return nil, err
} }
// This socket is used by a listener. // This function makes a network file descriptor for stream
if ulsa != nil && ursa == nil { // and datagram dialers, stream and datagram listeners.
//
// For dialers, they will require either named or unnamed
// sockets for their flights. We can assume that it's just a
// request from a dialer that wants a named socket when both
// laddr and raddr are not nil. A dialer will also require a
// connection setup initiated socket when raddr is not nil.
//
// For listeners and some dialers on datagram networks, they
// will only require named sockets. So we can assume that
// it's just for a listener or a datagram dialer when laddr is
// not nil but raddr is nil.
var lsa syscall.Sockaddr
if laddr != nil && raddr == nil {
// We provide a socket that listens to a wildcard // We provide a socket that listens to a wildcard
// address with reusable UDP port when the given ulsa // address with reusable UDP port when the given laddr
// is an appropriate UDP multicast address prefix. // is an appropriate UDP multicast address prefix.
// This makes it possible for a single UDP listener // This makes it possible for a single UDP listener
// to join multiple different group addresses, for // to join multiple different group addresses, for
// multiple UDP listeners that listen on the same UDP // multiple UDP listeners that listen on the same UDP
// port to join the same group address. // port to join the same group address.
if ulsa, err = listenerSockaddr(s, f, ulsa, toAddr); err != nil { if lsa, err = listenerSockaddr(s, f, laddr); err != nil {
closesocket(s)
return nil, err
}
} else if laddr != nil && raddr != nil {
if lsa, err = laddr.sockaddr(f); err != nil {
closesocket(s) closesocket(s)
return nil, err return nil, err
} }
} }
if ulsa != nil { if lsa != nil {
if err = syscall.Bind(s, ulsa); err != nil { if err = syscall.Bind(s, lsa); err != nil {
closesocket(s) closesocket(s)
return nil, err return nil, err
} }
...@@ -75,12 +94,19 @@ func socket(net string, f, t, p int, ipv6only bool, ulsa, ursa syscall.Sockaddr, ...@@ -75,12 +94,19 @@ func socket(net string, f, t, p int, ipv6only bool, ulsa, ursa syscall.Sockaddr,
return nil, err return nil, err
} }
// This socket is used by a dialer. var rsa syscall.Sockaddr
if ursa != nil { if raddr != nil {
rsa, err = raddr.sockaddr(f)
if err != nil {
return nil, err
}
}
if rsa != nil {
if !deadline.IsZero() { if !deadline.IsZero() {
setWriteDeadline(fd, deadline) setWriteDeadline(fd, deadline)
} }
if err = fd.connect(ulsa, ursa); err != nil { if err = fd.connect(lsa, rsa); err != nil {
fd.Close() fd.Close()
return nil, err return nil, err
} }
...@@ -90,13 +116,11 @@ func socket(net string, f, t, p int, ipv6only bool, ulsa, ursa syscall.Sockaddr, ...@@ -90,13 +116,11 @@ func socket(net string, f, t, p int, ipv6only bool, ulsa, ursa syscall.Sockaddr,
} }
} }
lsa, _ := syscall.Getsockname(s) lsa, _ = syscall.Getsockname(s)
laddr := toAddr(lsa) if rsa, _ = syscall.Getpeername(s); rsa != nil {
rsa, _ := syscall.Getpeername(s) fd.setAddr(toAddr(lsa), toAddr(rsa))
if rsa == nil { } else {
rsa = ursa fd.setAddr(toAddr(lsa), raddr)
} }
raddr := toAddr(rsa)
fd.setAddr(laddr, raddr)
return fd, nil return fd, nil
} }
...@@ -8,29 +8,29 @@ package net ...@@ -8,29 +8,29 @@ package net
import "syscall" import "syscall"
func listenerSockaddr(s, f int, la syscall.Sockaddr, toAddr func(syscall.Sockaddr) Addr) (syscall.Sockaddr, error) { func listenerSockaddr(s, f int, laddr sockaddr) (syscall.Sockaddr, error) {
a := toAddr(la) switch laddr := laddr.(type) {
if a == nil {
return la, nil
}
switch a := a.(type) {
case *TCPAddr, *UnixAddr: case *TCPAddr, *UnixAddr:
if err := setDefaultListenerSockopts(s); err != nil { if err := setDefaultListenerSockopts(s); err != nil {
return nil, err return nil, err
} }
return laddr.sockaddr(f)
case *UDPAddr: case *UDPAddr:
if a.IP.IsMulticast() { if laddr.IP != nil && laddr.IP.IsMulticast() {
if err := setDefaultMulticastSockopts(s); err != nil { if err := setDefaultMulticastSockopts(s); err != nil {
return nil, err return nil, err
} }
addr := *laddr
switch f { switch f {
case syscall.AF_INET: case syscall.AF_INET:
a.IP = IPv4zero addr.IP = IPv4zero
case syscall.AF_INET6: case syscall.AF_INET6:
a.IP = IPv6unspecified addr.IP = IPv6unspecified
} }
return a.sockaddr(f) laddr = &addr
} }
return laddr.sockaddr(f)
default:
return laddr.sockaddr(f)
} }
return la, nil
} }
...@@ -12,31 +12,31 @@ func maxListenerBacklog() int { ...@@ -12,31 +12,31 @@ func maxListenerBacklog() int {
return syscall.SOMAXCONN return syscall.SOMAXCONN
} }
func listenerSockaddr(s syscall.Handle, f int, la syscall.Sockaddr, toAddr func(syscall.Sockaddr) Addr) (syscall.Sockaddr, error) { func listenerSockaddr(s syscall.Handle, f int, laddr sockaddr) (syscall.Sockaddr, error) {
a := toAddr(la) switch laddr := laddr.(type) {
if a == nil {
return la, nil
}
switch a := a.(type) {
case *TCPAddr, *UnixAddr: case *TCPAddr, *UnixAddr:
if err := setDefaultListenerSockopts(s); err != nil { if err := setDefaultListenerSockopts(s); err != nil {
return nil, err return nil, err
} }
return laddr.sockaddr(f)
case *UDPAddr: case *UDPAddr:
if a.IP.IsMulticast() { if laddr.IP != nil && laddr.IP.IsMulticast() {
if err := setDefaultMulticastSockopts(s); err != nil { if err := setDefaultMulticastSockopts(s); err != nil {
return nil, err return nil, err
} }
addr := *laddr
switch f { switch f {
case syscall.AF_INET: case syscall.AF_INET:
a.IP = IPv4zero addr.IP = IPv4zero
case syscall.AF_INET6: case syscall.AF_INET6:
a.IP = IPv6unspecified addr.IP = IPv6unspecified
} }
return a.sockaddr(f) laddr = &addr
} }
return laddr.sockaddr(f)
default:
return laddr.sockaddr(f)
} }
return la, nil
} }
func sysSocket(f, t, p int) (syscall.Handle, error) { func sysSocket(f, t, p int) (syscall.Handle, error) {
......
...@@ -46,12 +46,15 @@ func (a *TCPAddr) isWildcard() bool { ...@@ -46,12 +46,15 @@ func (a *TCPAddr) isWildcard() bool {
} }
func (a *TCPAddr) sockaddr(family int) (syscall.Sockaddr, error) { func (a *TCPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
if a == nil {
return nil, nil
}
return ipToSockaddr(family, a.IP, a.Port, a.Zone) return ipToSockaddr(family, a.IP, a.Port, a.Zone)
} }
func (a *TCPAddr) toAddr() sockaddr { func (a *TCPAddr) toAddr() sockaddr {
if a == nil { // nil *TCPAddr if a == nil {
return nil // nil interface return nil
} }
return a return a
} }
...@@ -156,7 +159,7 @@ func DialTCP(net string, laddr, raddr *TCPAddr) (*TCPConn, error) { ...@@ -156,7 +159,7 @@ func DialTCP(net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
} }
func dialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time) (*TCPConn, error) { func dialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time) (*TCPConn, error) {
fd, err := internetSocket(net, laddr.toAddr(), raddr.toAddr(), deadline, syscall.SOCK_STREAM, 0, "dial", sockaddrToTCP) fd, err := internetSocket(net, laddr, raddr, deadline, syscall.SOCK_STREAM, 0, "dial", sockaddrToTCP)
// TCP has a rarely used mechanism called a 'simultaneous connection' in // TCP has a rarely used mechanism called a 'simultaneous connection' in
// which Dial("tcp", addr1, addr2) run on the machine at addr1 can // which Dial("tcp", addr1, addr2) run on the machine at addr1 can
...@@ -186,7 +189,7 @@ func dialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time) (*TCPConn, e ...@@ -186,7 +189,7 @@ func dialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time) (*TCPConn, e
if err == nil { if err == nil {
fd.Close() fd.Close()
} }
fd, err = internetSocket(net, laddr.toAddr(), raddr.toAddr(), deadline, syscall.SOCK_STREAM, 0, "dial", sockaddrToTCP) fd, err = internetSocket(net, laddr, raddr, deadline, syscall.SOCK_STREAM, 0, "dial", sockaddrToTCP)
} }
if err != nil { if err != nil {
...@@ -294,7 +297,7 @@ func ListenTCP(net string, laddr *TCPAddr) (*TCPListener, error) { ...@@ -294,7 +297,7 @@ func ListenTCP(net string, laddr *TCPAddr) (*TCPListener, error) {
if laddr == nil { if laddr == nil {
laddr = &TCPAddr{} laddr = &TCPAddr{}
} }
fd, err := internetSocket(net, laddr.toAddr(), nil, noDeadline, syscall.SOCK_STREAM, 0, "listen", sockaddrToTCP) fd, err := internetSocket(net, laddr, nil, noDeadline, syscall.SOCK_STREAM, 0, "listen", sockaddrToTCP)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
...@@ -39,12 +39,15 @@ func (a *UDPAddr) isWildcard() bool { ...@@ -39,12 +39,15 @@ func (a *UDPAddr) isWildcard() bool {
} }
func (a *UDPAddr) sockaddr(family int) (syscall.Sockaddr, error) { func (a *UDPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
if a == nil {
return nil, nil
}
return ipToSockaddr(family, a.IP, a.Port, a.Zone) return ipToSockaddr(family, a.IP, a.Port, a.Zone)
} }
func (a *UDPAddr) toAddr() sockaddr { func (a *UDPAddr) toAddr() sockaddr {
if a == nil { // nil *UDPAddr if a == nil {
return nil // nil interface return nil
} }
return a return a
} }
...@@ -173,7 +176,7 @@ func dialUDP(net string, laddr, raddr *UDPAddr, deadline time.Time) (*UDPConn, e ...@@ -173,7 +176,7 @@ func dialUDP(net string, laddr, raddr *UDPAddr, deadline time.Time) (*UDPConn, e
if raddr == nil { if raddr == nil {
return nil, &OpError{"dial", net, nil, errMissingAddress} return nil, &OpError{"dial", net, nil, errMissingAddress}
} }
fd, err := internetSocket(net, laddr.toAddr(), raddr.toAddr(), deadline, syscall.SOCK_DGRAM, 0, "dial", sockaddrToUDP) fd, err := internetSocket(net, laddr, raddr, deadline, syscall.SOCK_DGRAM, 0, "dial", sockaddrToUDP)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -196,7 +199,7 @@ func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error) { ...@@ -196,7 +199,7 @@ func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error) {
if laddr == nil { if laddr == nil {
laddr = &UDPAddr{} laddr = &UDPAddr{}
} }
fd, err := internetSocket(net, laddr.toAddr(), nil, noDeadline, syscall.SOCK_DGRAM, 0, "listen", sockaddrToUDP) fd, err := internetSocket(net, laddr, nil, noDeadline, syscall.SOCK_DGRAM, 0, "listen", sockaddrToUDP)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -216,7 +219,7 @@ func ListenMulticastUDP(net string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, e ...@@ -216,7 +219,7 @@ func ListenMulticastUDP(net string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, e
if gaddr == nil || gaddr.IP == nil { if gaddr == nil || gaddr.IP == nil {
return nil, &OpError{"listen", net, nil, errMissingAddress} return nil, &OpError{"listen", net, nil, errMissingAddress}
} }
fd, err := internetSocket(net, gaddr.toAddr(), nil, noDeadline, syscall.SOCK_DGRAM, 0, "listen", sockaddrToUDP) fd, err := internetSocket(net, gaddr, nil, noDeadline, syscall.SOCK_DGRAM, 0, "listen", sockaddrToUDP)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
...@@ -13,7 +13,7 @@ import ( ...@@ -13,7 +13,7 @@ import (
"time" "time"
) )
func unixSocket(net string, laddr, raddr *UnixAddr, mode string, deadline time.Time) (*netFD, error) { func unixSocket(net string, laddr, raddr sockaddr, mode string, deadline time.Time) (*netFD, error) {
var sotype int var sotype int
switch net { switch net {
case "unix": case "unix":
...@@ -26,19 +26,18 @@ func unixSocket(net string, laddr, raddr *UnixAddr, mode string, deadline time.T ...@@ -26,19 +26,18 @@ func unixSocket(net string, laddr, raddr *UnixAddr, mode string, deadline time.T
return nil, UnknownNetworkError(net) return nil, UnknownNetworkError(net)
} }
var la, ra syscall.Sockaddr
switch mode { switch mode {
case "dial": case "dial":
if !laddr.isWildcard() { if laddr != nil && laddr.isWildcard() {
la = &syscall.SockaddrUnix{Name: laddr.Name} laddr = nil
} }
if raddr != nil { if raddr != nil && raddr.isWildcard() {
ra = &syscall.SockaddrUnix{Name: raddr.Name} raddr = nil
} else if sotype != syscall.SOCK_DGRAM || laddr.isWildcard() { }
if raddr == nil && (sotype != syscall.SOCK_DGRAM || laddr == nil) {
return nil, &OpError{Op: mode, Net: net, Err: errMissingAddress} return nil, &OpError{Op: mode, Net: net, Err: errMissingAddress}
} }
case "listen": case "listen":
la = &syscall.SockaddrUnix{Name: laddr.Name}
default: default:
return nil, errors.New("unknown mode: " + mode) return nil, errors.New("unknown mode: " + mode)
} }
...@@ -50,7 +49,7 @@ func unixSocket(net string, laddr, raddr *UnixAddr, mode string, deadline time.T ...@@ -50,7 +49,7 @@ func unixSocket(net string, laddr, raddr *UnixAddr, mode string, deadline time.T
f = sockaddrToUnixpacket f = sockaddrToUnixpacket
} }
fd, err := socket(net, syscall.AF_UNIX, sotype, 0, false, la, ra, deadline, f) fd, err := socket(net, syscall.AF_UNIX, sotype, 0, false, laddr, raddr, deadline, f)
if err != nil { if err != nil {
goto error goto error
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment