mirror of
https://github.com/golang/go
synced 2024-11-20 09:54:45 -07:00
net: close fds eagerly in DialTimeout
Integrates with the pollserver now. Uses the old implementation on windows and plan9. Fixes #2631 R=paul, iant, adg, bendaglish, rsc CC=golang-dev https://golang.org/cl/6815049
This commit is contained in:
parent
a384b5b9c3
commit
ef6806fb13
@ -5,6 +5,7 @@
|
|||||||
package net
|
package net
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"runtime"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -36,7 +37,7 @@ func parseDialNetwork(net string) (afnet string, proto int, err error) {
|
|||||||
return "", 0, UnknownNetworkError(net)
|
return "", 0, UnknownNetworkError(net)
|
||||||
}
|
}
|
||||||
|
|
||||||
func resolveNetAddr(op, net, addr string) (afnet string, a Addr, err error) {
|
func resolveNetAddr(op, net, addr string, deadline time.Time) (afnet string, a Addr, err error) {
|
||||||
afnet, _, err = parseDialNetwork(net)
|
afnet, _, err = parseDialNetwork(net)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, &OpError{op, net, nil, err}
|
return "", nil, &OpError{op, net, nil, err}
|
||||||
@ -44,25 +45,25 @@ func resolveNetAddr(op, net, addr string) (afnet string, a Addr, err error) {
|
|||||||
if op == "dial" && addr == "" {
|
if op == "dial" && addr == "" {
|
||||||
return "", nil, &OpError{op, net, nil, errMissingAddress}
|
return "", nil, &OpError{op, net, nil, errMissingAddress}
|
||||||
}
|
}
|
||||||
|
a, err = resolveAfnetAddr(afnet, addr, deadline)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func resolveAfnetAddr(afnet, addr string, deadline time.Time) (Addr, error) {
|
||||||
|
if addr == "" {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
switch afnet {
|
switch afnet {
|
||||||
case "tcp", "tcp4", "tcp6":
|
case "tcp", "tcp4", "tcp6":
|
||||||
if addr != "" {
|
return resolveTCPAddr(afnet, addr, deadline)
|
||||||
a, err = ResolveTCPAddr(afnet, addr)
|
|
||||||
}
|
|
||||||
case "udp", "udp4", "udp6":
|
case "udp", "udp4", "udp6":
|
||||||
if addr != "" {
|
return resolveUDPAddr(afnet, addr, deadline)
|
||||||
a, err = ResolveUDPAddr(afnet, addr)
|
|
||||||
}
|
|
||||||
case "ip", "ip4", "ip6":
|
case "ip", "ip4", "ip6":
|
||||||
if addr != "" {
|
return resolveIPAddr(afnet, addr, deadline)
|
||||||
a, err = ResolveIPAddr(afnet, addr)
|
|
||||||
}
|
|
||||||
case "unix", "unixgram", "unixpacket":
|
case "unix", "unixgram", "unixpacket":
|
||||||
if addr != "" {
|
return ResolveUnixAddr(afnet, addr)
|
||||||
a, err = ResolveUnixAddr(afnet, addr)
|
|
||||||
}
|
}
|
||||||
}
|
return nil, nil
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dial connects to the address addr on the network net.
|
// Dial connects to the address addr on the network net.
|
||||||
@ -89,23 +90,23 @@ func resolveNetAddr(op, net, addr string) (afnet string, a Addr, err error) {
|
|||||||
// Dial("ip6:ospf", "::1")
|
// Dial("ip6:ospf", "::1")
|
||||||
//
|
//
|
||||||
func Dial(net, addr string) (Conn, error) {
|
func Dial(net, addr string) (Conn, error) {
|
||||||
_, addri, err := resolveNetAddr("dial", net, addr)
|
_, addri, err := resolveNetAddr("dial", net, addr, noDeadline)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return dialAddr(net, addr, addri)
|
return dialAddr(net, addr, addri, noDeadline)
|
||||||
}
|
}
|
||||||
|
|
||||||
func dialAddr(net, addr string, addri Addr) (c Conn, err error) {
|
func dialAddr(net, addr string, addri Addr, deadline time.Time) (c Conn, err error) {
|
||||||
switch ra := addri.(type) {
|
switch ra := addri.(type) {
|
||||||
case *TCPAddr:
|
case *TCPAddr:
|
||||||
c, err = DialTCP(net, nil, ra)
|
c, err = dialTCP(net, nil, ra, deadline)
|
||||||
case *UDPAddr:
|
case *UDPAddr:
|
||||||
c, err = DialUDP(net, nil, ra)
|
c, err = dialUDP(net, nil, ra, deadline)
|
||||||
case *IPAddr:
|
case *IPAddr:
|
||||||
c, err = DialIP(net, nil, ra)
|
c, err = dialIP(net, nil, ra, deadline)
|
||||||
case *UnixAddr:
|
case *UnixAddr:
|
||||||
c, err = DialUnix(net, nil, ra)
|
c, err = dialUnix(net, nil, ra, deadline)
|
||||||
default:
|
default:
|
||||||
err = &OpError{"dial", net + " " + addr, nil, UnknownNetworkError(net)}
|
err = &OpError{"dial", net + " " + addr, nil, UnknownNetworkError(net)}
|
||||||
}
|
}
|
||||||
@ -115,13 +116,31 @@ func dialAddr(net, addr string, addri Addr) (c Conn, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const useDialTimeoutRace = runtime.GOOS == "windows" || runtime.GOOS == "plan9"
|
||||||
|
|
||||||
// DialTimeout acts like Dial but takes a timeout.
|
// DialTimeout acts like Dial but takes a timeout.
|
||||||
// The timeout includes name resolution, if required.
|
// The timeout includes name resolution, if required.
|
||||||
func DialTimeout(net, addr string, timeout time.Duration) (Conn, error) {
|
func DialTimeout(net, addr string, timeout time.Duration) (Conn, error) {
|
||||||
// TODO(bradfitz): the timeout should be pushed down into the
|
if useDialTimeoutRace {
|
||||||
// net package's event loop, so on timeout to dead hosts we
|
// On windows and plan9, use the relatively inefficient
|
||||||
// don't have a goroutine sticking around for the default of
|
// goroutine-racing implementation of DialTimeout that
|
||||||
// ~3 minutes.
|
// doesn't push down deadlines to the pollster.
|
||||||
|
// TODO: remove this once those are implemented.
|
||||||
|
return dialTimeoutRace(net, addr, timeout)
|
||||||
|
}
|
||||||
|
deadline := time.Now().Add(timeout)
|
||||||
|
_, addri, err := resolveNetAddr("dial", net, addr, deadline)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return dialAddr(net, addr, addri, deadline)
|
||||||
|
}
|
||||||
|
|
||||||
|
// dialTimeoutRace is the old implementation of DialTimeout, still used
|
||||||
|
// on operating systems where the deadline hasn't been pushed down
|
||||||
|
// into the pollserver.
|
||||||
|
// TODO: fix this on Windows and plan9.
|
||||||
|
func dialTimeoutRace(net, addr string, timeout time.Duration) (Conn, error) {
|
||||||
t := time.NewTimer(timeout)
|
t := time.NewTimer(timeout)
|
||||||
defer t.Stop()
|
defer t.Stop()
|
||||||
type pair struct {
|
type pair struct {
|
||||||
@ -131,13 +150,13 @@ func DialTimeout(net, addr string, timeout time.Duration) (Conn, error) {
|
|||||||
ch := make(chan pair, 1)
|
ch := make(chan pair, 1)
|
||||||
resolvedAddr := make(chan Addr, 1)
|
resolvedAddr := make(chan Addr, 1)
|
||||||
go func() {
|
go func() {
|
||||||
_, addri, err := resolveNetAddr("dial", net, addr)
|
_, addri, err := resolveNetAddr("dial", net, addr, noDeadline)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ch <- pair{nil, err}
|
ch <- pair{nil, err}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
resolvedAddr <- addri // in case we need it for OpError
|
resolvedAddr <- addri // in case we need it for OpError
|
||||||
c, err := dialAddr(net, addr, addri)
|
c, err := dialAddr(net, addr, addri, noDeadline)
|
||||||
ch <- pair{c, err}
|
ch <- pair{c, err}
|
||||||
}()
|
}()
|
||||||
select {
|
select {
|
||||||
@ -175,7 +194,7 @@ func (a stringAddr) String() string { return a.addr }
|
|||||||
// The network string net must be a stream-oriented network:
|
// The network string net must be a stream-oriented network:
|
||||||
// "tcp", "tcp4", "tcp6", "unix" or "unixpacket".
|
// "tcp", "tcp4", "tcp6", "unix" or "unixpacket".
|
||||||
func Listen(net, laddr string) (Listener, error) {
|
func Listen(net, laddr string) (Listener, error) {
|
||||||
afnet, a, err := resolveNetAddr("listen", net, laddr)
|
afnet, a, err := resolveNetAddr("listen", net, laddr, noDeadline)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -200,7 +219,7 @@ func Listen(net, laddr string) (Listener, error) {
|
|||||||
// The network string net must be a packet-oriented network:
|
// The network string net must be a packet-oriented network:
|
||||||
// "udp", "udp4", "udp6", "ip", "ip4", "ip6" or "unixgram".
|
// "udp", "udp4", "udp6", "ip", "ip4", "ip6" or "unixgram".
|
||||||
func ListenPacket(net, addr string) (PacketConn, error) {
|
func ListenPacket(net, addr string) (PacketConn, error) {
|
||||||
afnet, a, err := resolveNetAddr("listen", net, addr)
|
afnet, a, err := resolveNetAddr("listen", net, addr, noDeadline)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,8 @@ package net
|
|||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
"runtime"
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
@ -222,3 +224,79 @@ func TestDialError(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDialTimeoutFDLeak(t *testing.T) {
|
||||||
|
if runtime.GOOS != "linux" {
|
||||||
|
// TODO(bradfitz): test on other platforms
|
||||||
|
t.Logf("skipping test on %s", runtime.GOOS)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ln := newLocalListener(t)
|
||||||
|
defer ln.Close()
|
||||||
|
|
||||||
|
type connErr struct {
|
||||||
|
conn Conn
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
dials := listenerBacklog + 100
|
||||||
|
maxGoodConnect := listenerBacklog + 5 // empirically 131 good ones (of 128). who knows?
|
||||||
|
resc := make(chan connErr)
|
||||||
|
for i := 0; i < dials; i++ {
|
||||||
|
go func() {
|
||||||
|
conn, err := DialTimeout("tcp", ln.Addr().String(), 500*time.Millisecond)
|
||||||
|
resc <- connErr{conn, err}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
var firstErr string
|
||||||
|
var ngood int
|
||||||
|
var toClose []io.Closer
|
||||||
|
for i := 0; i < dials; i++ {
|
||||||
|
ce := <-resc
|
||||||
|
if ce.err == nil {
|
||||||
|
ngood++
|
||||||
|
if ngood > maxGoodConnect {
|
||||||
|
t.Errorf("%d good connects; expected at most %d", ngood, maxGoodConnect)
|
||||||
|
}
|
||||||
|
toClose = append(toClose, ce.conn)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
err := ce.err
|
||||||
|
if firstErr == "" {
|
||||||
|
firstErr = err.Error()
|
||||||
|
} else if err.Error() != firstErr {
|
||||||
|
t.Fatalf("inconsistent error messages: first was %q, then later %q", firstErr, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, c := range toClose {
|
||||||
|
c.Close()
|
||||||
|
}
|
||||||
|
for i := 0; i < 100; i++ {
|
||||||
|
if got := numFD(); got < dials {
|
||||||
|
// Test passes.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
}
|
||||||
|
if got := numFD(); got >= dials {
|
||||||
|
t.Errorf("num fds after %d timeouts = %d; want <%d", dials, got, dials)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func numFD() int {
|
||||||
|
if runtime.GOOS == "linux" {
|
||||||
|
f, err := os.Open("/proc/self/fd")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
names, err := f.Readdirnames(0)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return len(names)
|
||||||
|
}
|
||||||
|
// All tests using this should be skipped anyway, but:
|
||||||
|
panic("numFDs not implemented on " + runtime.GOOS)
|
||||||
|
}
|
||||||
|
@ -162,7 +162,7 @@ func (s *pollServer) CheckDeadlines() {
|
|||||||
// TODO(rsc): This will need to be handled more efficiently,
|
// TODO(rsc): This will need to be handled more efficiently,
|
||||||
// probably with a heap indexed by wakeup time.
|
// probably with a heap indexed by wakeup time.
|
||||||
|
|
||||||
var next_deadline int64
|
var nextDeadline int64
|
||||||
for key, fd := range s.pending {
|
for key, fd := range s.pending {
|
||||||
var t int64
|
var t int64
|
||||||
var mode int
|
var mode int
|
||||||
@ -187,12 +187,12 @@ func (s *pollServer) CheckDeadlines() {
|
|||||||
fd.wdeadline = -1
|
fd.wdeadline = -1
|
||||||
}
|
}
|
||||||
s.WakeFD(fd, mode, nil)
|
s.WakeFD(fd, mode, nil)
|
||||||
} else if next_deadline == 0 || t < next_deadline {
|
} else if nextDeadline == 0 || t < nextDeadline {
|
||||||
next_deadline = t
|
nextDeadline = t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s.deadline = next_deadline
|
s.deadline = nextDeadline
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *pollServer) Run() {
|
func (s *pollServer) Run() {
|
||||||
@ -332,10 +332,14 @@ func (fd *netFD) name() string {
|
|||||||
|
|
||||||
func (fd *netFD) connect(ra syscall.Sockaddr) error {
|
func (fd *netFD) connect(ra syscall.Sockaddr) error {
|
||||||
err := syscall.Connect(fd.sysfd, ra)
|
err := syscall.Connect(fd.sysfd, ra)
|
||||||
|
hadTimeout := fd.wdeadline > 0
|
||||||
if err == syscall.EINPROGRESS {
|
if err == syscall.EINPROGRESS {
|
||||||
if err = fd.pollServer.WaitWrite(fd); err != nil {
|
if err = fd.pollServer.WaitWrite(fd); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if hadTimeout && fd.wdeadline < 0 {
|
||||||
|
return errTimeout
|
||||||
|
}
|
||||||
var e int
|
var e int
|
||||||
e, err = syscall.GetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
|
e, err = syscall.GetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -6,6 +6,10 @@
|
|||||||
|
|
||||||
package net
|
package net
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
// IPAddr represents the address of an IP end point.
|
// IPAddr represents the address of an IP end point.
|
||||||
type IPAddr struct {
|
type IPAddr struct {
|
||||||
IP IP
|
IP IP
|
||||||
@ -26,7 +30,11 @@ func (a *IPAddr) String() string {
|
|||||||
// "ip", "ip4" or "ip6". A literal IPv6 host address must be
|
// "ip", "ip4" or "ip6". A literal IPv6 host address must be
|
||||||
// enclosed in square brackets, as in "[::]".
|
// enclosed in square brackets, as in "[::]".
|
||||||
func ResolveIPAddr(net, addr string) (*IPAddr, error) {
|
func ResolveIPAddr(net, addr string) (*IPAddr, error) {
|
||||||
ip, err := hostToIP(net, addr)
|
return resolveIPAddr(net, addr, noDeadline)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resolveIPAddr(net, addr string, deadline time.Time) (*IPAddr, error) {
|
||||||
|
ip, err := hostToIP(net, addr, deadline)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -34,7 +42,7 @@ func ResolveIPAddr(net, addr string) (*IPAddr, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Convert "host" into IP address.
|
// Convert "host" into IP address.
|
||||||
func hostToIP(net, host string) (ip IP, err error) {
|
func hostToIP(net, host string, deadline time.Time) (ip IP, err error) {
|
||||||
var addr IP
|
var addr IP
|
||||||
// Try as an IP address.
|
// Try as an IP address.
|
||||||
addr = ParseIP(host)
|
addr = ParseIP(host)
|
||||||
@ -47,7 +55,7 @@ func hostToIP(net, host string) (ip IP, err error) {
|
|||||||
filter = ipv6only
|
filter = ipv6only
|
||||||
}
|
}
|
||||||
// Not an IP address. Try as a DNS name.
|
// Not an IP address. Try as a DNS name.
|
||||||
addrs, err1 := LookupHost(host)
|
addrs, err1 := lookupHostDeadline(host, deadline)
|
||||||
if err1 != nil {
|
if err1 != nil {
|
||||||
err = err1
|
err = err1
|
||||||
goto Error
|
goto Error
|
||||||
|
@ -130,6 +130,10 @@ func (c *IPConn) WriteMsgIP(b, oob []byte, addr *IPAddr) (n, oobn int, err error
|
|||||||
// netProto, which must be "ip", "ip4", or "ip6" followed by a colon
|
// netProto, which must be "ip", "ip4", or "ip6" followed by a colon
|
||||||
// and a protocol number or name.
|
// and a protocol number or name.
|
||||||
func DialIP(netProto string, laddr, raddr *IPAddr) (*IPConn, error) {
|
func DialIP(netProto string, laddr, raddr *IPAddr) (*IPConn, error) {
|
||||||
|
return dialIP(netProto, laddr, raddr, noDeadline)
|
||||||
|
}
|
||||||
|
|
||||||
|
func dialIP(netProto string, laddr, raddr *IPAddr, deadline time.Time) (*IPConn, error) {
|
||||||
return nil, syscall.EPLAN9
|
return nil, syscall.EPLAN9
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ package net
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func sockaddrToIP(sa syscall.Sockaddr) Addr {
|
func sockaddrToIP(sa syscall.Sockaddr) Addr {
|
||||||
@ -163,6 +164,10 @@ func (c *IPConn) WriteMsgIP(b, oob []byte, addr *IPAddr) (n, oobn int, err error
|
|||||||
// DialIP connects to the remote address raddr on the network protocol netProto,
|
// DialIP connects to the remote address raddr on the network protocol netProto,
|
||||||
// which must be "ip", "ip4", or "ip6" followed by a colon and a protocol number or name.
|
// which must be "ip", "ip4", or "ip6" followed by a colon and a protocol number or name.
|
||||||
func DialIP(netProto string, laddr, raddr *IPAddr) (*IPConn, error) {
|
func DialIP(netProto string, laddr, raddr *IPAddr) (*IPConn, error) {
|
||||||
|
return dialIP(netProto, laddr, raddr, noDeadline)
|
||||||
|
}
|
||||||
|
|
||||||
|
func dialIP(netProto string, laddr, raddr *IPAddr, deadline time.Time) (*IPConn, error) {
|
||||||
net, proto, err := parseDialNetwork(netProto)
|
net, proto, err := parseDialNetwork(netProto)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -175,7 +180,7 @@ func DialIP(netProto string, laddr, raddr *IPAddr) (*IPConn, error) {
|
|||||||
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(), syscall.SOCK_RAW, proto, "dial", sockaddrToIP)
|
fd, err := internetSocket(net, laddr.toAddr(), raddr.toAddr(), deadline, syscall.SOCK_RAW, proto, "dial", sockaddrToIP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -196,7 +201,7 @@ func ListenIP(netProto string, laddr *IPAddr) (*IPConn, error) {
|
|||||||
default:
|
default:
|
||||||
return nil, UnknownNetworkError(net)
|
return nil, UnknownNetworkError(net)
|
||||||
}
|
}
|
||||||
fd, err := internetSocket(net, laddr.toAddr(), nil, syscall.SOCK_RAW, proto, "listen", sockaddrToIP)
|
fd, err := internetSocket(net, laddr.toAddr(), nil, noDeadline, syscall.SOCK_RAW, proto, "listen", sockaddrToIP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,9 @@
|
|||||||
|
|
||||||
package net
|
package net
|
||||||
|
|
||||||
var supportsIPv6, supportsIPv4map bool
|
import "time"
|
||||||
|
|
||||||
func init() {
|
var supportsIPv6, supportsIPv4map = probeIPv6Stack()
|
||||||
sysInit()
|
|
||||||
supportsIPv6, supportsIPv4map = probeIPv6Stack()
|
|
||||||
}
|
|
||||||
|
|
||||||
func firstFavoriteAddr(filter func(IP) IP, addrs []string) (addr IP) {
|
func firstFavoriteAddr(filter func(IP) IP, addrs []string) (addr IP) {
|
||||||
if filter == nil {
|
if filter == nil {
|
||||||
@ -103,7 +100,7 @@ func JoinHostPort(host, port string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Convert "host:port" into IP address and port.
|
// Convert "host:port" into IP address and port.
|
||||||
func hostPortToIP(net, hostport string) (ip IP, iport int, err error) {
|
func hostPortToIP(net, hostport string, deadline time.Time) (ip IP, iport int, err error) {
|
||||||
host, port, err := SplitHostPort(hostport)
|
host, port, err := SplitHostPort(hostport)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
@ -122,7 +119,7 @@ func hostPortToIP(net, hostport string) (ip IP, iport int, err error) {
|
|||||||
filter = ipv6only
|
filter = ipv6only
|
||||||
}
|
}
|
||||||
// Not an IP address. Try as a DNS name.
|
// Not an IP address. Try as a DNS name.
|
||||||
addrs, err := LookupHost(host)
|
addrs, err := lookupHostDeadline(host, deadline)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,10 @@
|
|||||||
|
|
||||||
package net
|
package net
|
||||||
|
|
||||||
import "syscall"
|
import (
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
// Should we try to use the IPv4 socket interface if we're
|
// Should we try to use the IPv4 socket interface if we're
|
||||||
// only dealing with IPv4 sockets? As long as the host system
|
// only dealing with IPv4 sockets? As long as the host system
|
||||||
@ -125,7 +128,7 @@ type sockaddr interface {
|
|||||||
sockaddr(family int) (syscall.Sockaddr, error)
|
sockaddr(family int) (syscall.Sockaddr, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func internetSocket(net string, laddr, raddr sockaddr, 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
|
var la, ra syscall.Sockaddr
|
||||||
family, ipv6only := favoriteAddrFamily(net, laddr, raddr, mode)
|
family, ipv6only := favoriteAddrFamily(net, laddr, raddr, mode)
|
||||||
if laddr != nil {
|
if laddr != nil {
|
||||||
@ -138,7 +141,7 @@ func internetSocket(net string, laddr, raddr sockaddr, sotype, proto int, mode s
|
|||||||
goto Error
|
goto Error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fd, err = socket(net, family, sotype, proto, ipv6only, la, ra, toAddr)
|
fd, err = socket(net, family, sotype, proto, ipv6only, la, ra, deadline, toAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
goto Error
|
goto Error
|
||||||
}
|
}
|
||||||
|
@ -4,12 +4,53 @@
|
|||||||
|
|
||||||
package net
|
package net
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
// LookupHost looks up the given host using the local resolver.
|
// LookupHost looks up the given host using the local resolver.
|
||||||
// It returns an array of that host's addresses.
|
// It returns an array of that host's addresses.
|
||||||
func LookupHost(host string) (addrs []string, err error) {
|
func LookupHost(host string) (addrs []string, err error) {
|
||||||
return lookupHost(host)
|
return lookupHost(host)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func lookupHostDeadline(host string, deadline time.Time) (addrs []string, err error) {
|
||||||
|
if deadline.IsZero() {
|
||||||
|
return lookupHost(host)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(bradfitz): consider pushing the deadline down into the
|
||||||
|
// name resolution functions. But that involves fixing it for
|
||||||
|
// the native Go resolver, cgo, Windows, etc.
|
||||||
|
//
|
||||||
|
// In the meantime, just use a goroutine. Most users affected
|
||||||
|
// by http://golang.org/issue/2631 are due to TCP connections
|
||||||
|
// to unresponsive hosts, not DNS.
|
||||||
|
timeout := deadline.Sub(time.Now())
|
||||||
|
if timeout <= 0 {
|
||||||
|
err = errTimeout
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t := time.NewTimer(timeout)
|
||||||
|
defer t.Stop()
|
||||||
|
type res struct {
|
||||||
|
addrs []string
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
resc := make(chan res, 1)
|
||||||
|
go func() {
|
||||||
|
a, err := lookupHost(host)
|
||||||
|
resc <- res{a, err}
|
||||||
|
}()
|
||||||
|
select {
|
||||||
|
case <-t.C:
|
||||||
|
err = errTimeout
|
||||||
|
case r := <-resc:
|
||||||
|
addrs, err = r.addrs, r.err
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// LookupIP looks up host using the local resolver.
|
// LookupIP looks up host using the local resolver.
|
||||||
// It returns an array of that host's IPv4 and IPv6 addresses.
|
// It returns an array of that host's IPv4 and IPv6 addresses.
|
||||||
func LookupIP(host string) (addrs []IP, err error) {
|
func LookupIP(host string) (addrs []IP, err error) {
|
||||||
|
@ -204,6 +204,8 @@ func (e *OpError) Temporary() bool {
|
|||||||
return ok && t.Temporary()
|
return ok && t.Temporary()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var noDeadline = time.Time{}
|
||||||
|
|
||||||
type timeout interface {
|
type timeout interface {
|
||||||
Timeout() bool
|
Timeout() bool
|
||||||
}
|
}
|
||||||
|
@ -11,12 +11,13 @@ package net
|
|||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var listenerBacklog = maxListenerBacklog()
|
var listenerBacklog = maxListenerBacklog()
|
||||||
|
|
||||||
// Generic socket creation.
|
// Generic socket creation.
|
||||||
func socket(net string, f, t, p int, ipv6only bool, ulsa, ursa syscall.Sockaddr, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err error) {
|
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) {
|
||||||
// See ../syscall/exec_unix.go for description of ForkLock.
|
// See ../syscall/exec_unix.go for description of ForkLock.
|
||||||
syscall.ForkLock.RLock()
|
syscall.ForkLock.RLock()
|
||||||
s, err := syscall.Socket(f, t, p)
|
s, err := syscall.Socket(f, t, p)
|
||||||
@ -50,12 +51,16 @@ func socket(net string, f, t, p int, ipv6only bool, ulsa, ursa syscall.Sockaddr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ursa != nil {
|
if ursa != nil {
|
||||||
|
if !deadline.IsZero() {
|
||||||
|
fd.wdeadline = deadline.UnixNano()
|
||||||
|
}
|
||||||
if err = fd.connect(ursa); err != nil {
|
if err = fd.connect(ursa); err != nil {
|
||||||
closesocket(s)
|
closesocket(s)
|
||||||
fd.Close()
|
fd.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
fd.isConnected = true
|
fd.isConnected = true
|
||||||
|
fd.wdeadline = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
lsa, _ := syscall.Getsockname(s)
|
lsa, _ := syscall.Getsockname(s)
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
package net
|
package net
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
// TCPAddr represents the address of a TCP end point.
|
// TCPAddr represents the address of a TCP end point.
|
||||||
type TCPAddr struct {
|
type TCPAddr struct {
|
||||||
IP IP
|
IP IP
|
||||||
@ -28,7 +30,11 @@ func (a *TCPAddr) String() string {
|
|||||||
// "tcp4" or "tcp6". A literal IPv6 host address must be
|
// "tcp4" or "tcp6". A literal IPv6 host address must be
|
||||||
// enclosed in square brackets, as in "[::]:80".
|
// enclosed in square brackets, as in "[::]:80".
|
||||||
func ResolveTCPAddr(net, addr string) (*TCPAddr, error) {
|
func ResolveTCPAddr(net, addr string) (*TCPAddr, error) {
|
||||||
ip, port, err := hostPortToIP(net, addr)
|
return resolveTCPAddr(net, addr, noDeadline)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resolveTCPAddr(net, addr string, deadline time.Time) (*TCPAddr, error) {
|
||||||
|
ip, port, err := hostPortToIP(net, addr, deadline)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,10 @@
|
|||||||
|
|
||||||
package net
|
package net
|
||||||
|
|
||||||
import "syscall"
|
import (
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
// TCPConn is an implementation of the Conn interface for TCP network
|
// TCPConn is an implementation of the Conn interface for TCP network
|
||||||
// connections.
|
// connections.
|
||||||
@ -36,6 +39,13 @@ func (c *TCPConn) CloseWrite() error {
|
|||||||
// which must be "tcp", "tcp4", or "tcp6". If laddr is not nil, it is
|
// which must be "tcp", "tcp4", or "tcp6". If laddr is not nil, it is
|
||||||
// used as the local address for the connection.
|
// used as the local address for the connection.
|
||||||
func DialTCP(net string, laddr, raddr *TCPAddr) (c *TCPConn, err error) {
|
func DialTCP(net string, laddr, raddr *TCPAddr) (c *TCPConn, err error) {
|
||||||
|
return dialTCP(net, laddr, raddr, noDeadline)
|
||||||
|
}
|
||||||
|
|
||||||
|
func dialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time) (c *TCPConn, err error) {
|
||||||
|
if !deadline.IsZero() {
|
||||||
|
panic("net.dialTCP: deadline not implemented on Plan 9")
|
||||||
|
}
|
||||||
switch net {
|
switch net {
|
||||||
case "tcp", "tcp4", "tcp6":
|
case "tcp", "tcp4", "tcp6":
|
||||||
default:
|
default:
|
||||||
|
@ -143,11 +143,15 @@ func (c *TCPConn) SetNoDelay(noDelay bool) error {
|
|||||||
// which must be "tcp", "tcp4", or "tcp6". If laddr is not nil, it is used
|
// which must be "tcp", "tcp4", or "tcp6". If laddr is not nil, it is used
|
||||||
// as the local address for the connection.
|
// as the local address for the connection.
|
||||||
func DialTCP(net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
|
func DialTCP(net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
|
||||||
|
return dialTCP(net, laddr, raddr, noDeadline)
|
||||||
|
}
|
||||||
|
|
||||||
|
func dialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time) (*TCPConn, error) {
|
||||||
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(), syscall.SOCK_STREAM, 0, "dial", sockaddrToTCP)
|
fd, err := internetSocket(net, laddr.toAddr(), raddr.toAddr(), 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
|
||||||
@ -177,7 +181,7 @@ func DialTCP(net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
fd.Close()
|
fd.Close()
|
||||||
}
|
}
|
||||||
fd, err = internetSocket(net, laddr.toAddr(), raddr.toAddr(), syscall.SOCK_STREAM, 0, "dial", sockaddrToTCP)
|
fd, err = internetSocket(net, laddr.toAddr(), raddr.toAddr(), deadline, syscall.SOCK_STREAM, 0, "dial", sockaddrToTCP)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -225,7 +229,7 @@ type TCPListener struct {
|
|||||||
// If laddr has a port of 0, it means to listen on some available port.
|
// If laddr has a port of 0, it means to listen on some available port.
|
||||||
// The caller can use l.Addr() to retrieve the chosen address.
|
// The caller can use l.Addr() to retrieve the chosen address.
|
||||||
func ListenTCP(net string, laddr *TCPAddr) (*TCPListener, error) {
|
func ListenTCP(net string, laddr *TCPAddr) (*TCPListener, error) {
|
||||||
fd, err := internetSocket(net, laddr.toAddr(), nil, syscall.SOCK_STREAM, 0, "listen", sockaddrToTCP)
|
fd, err := internetSocket(net, laddr.toAddr(), nil, noDeadline, syscall.SOCK_STREAM, 0, "listen", sockaddrToTCP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,10 @@
|
|||||||
|
|
||||||
package net
|
package net
|
||||||
|
|
||||||
import "errors"
|
import (
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
var ErrWriteToConnected = errors.New("use of WriteTo with pre-connected UDP")
|
var ErrWriteToConnected = errors.New("use of WriteTo with pre-connected UDP")
|
||||||
|
|
||||||
@ -32,7 +35,11 @@ func (a *UDPAddr) String() string {
|
|||||||
// "udp4" or "udp6". A literal IPv6 host address must be
|
// "udp4" or "udp6". A literal IPv6 host address must be
|
||||||
// enclosed in square brackets, as in "[::]:80".
|
// enclosed in square brackets, as in "[::]:80".
|
||||||
func ResolveUDPAddr(net, addr string) (*UDPAddr, error) {
|
func ResolveUDPAddr(net, addr string) (*UDPAddr, error) {
|
||||||
ip, port, err := hostPortToIP(net, addr)
|
return resolveUDPAddr(net, addr, noDeadline)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resolveUDPAddr(net, addr string, deadline time.Time) (*UDPAddr, error) {
|
||||||
|
ip, port, err := hostPortToIP(net, addr, deadline)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"os"
|
"os"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// UDPConn is the implementation of the Conn and PacketConn
|
// UDPConn is the implementation of the Conn and PacketConn
|
||||||
@ -122,6 +123,13 @@ func (c *UDPConn) WriteMsgUDP(b, oob []byte, addr *UDPAddr) (n, oobn int, err er
|
|||||||
// which must be "udp", "udp4", or "udp6". If laddr is not nil, it is
|
// which must be "udp", "udp4", or "udp6". If laddr is not nil, it is
|
||||||
// used as the local address for the connection.
|
// used as the local address for the connection.
|
||||||
func DialUDP(net string, laddr, raddr *UDPAddr) (c *UDPConn, err error) {
|
func DialUDP(net string, laddr, raddr *UDPAddr) (c *UDPConn, err error) {
|
||||||
|
return dialUDP(net, laddr, raddr, noDeadline)
|
||||||
|
}
|
||||||
|
|
||||||
|
func dialUDP(net string, laddr, raddr *UDPAddr, deadline time.Time) (c *UDPConn, err error) {
|
||||||
|
if !deadline.IsZero() {
|
||||||
|
panic("net.dialUDP: deadline not implemented on Plan 9")
|
||||||
|
}
|
||||||
switch net {
|
switch net {
|
||||||
case "udp", "udp4", "udp6":
|
case "udp", "udp4", "udp6":
|
||||||
default:
|
default:
|
||||||
|
@ -8,7 +8,10 @@
|
|||||||
|
|
||||||
package net
|
package net
|
||||||
|
|
||||||
import "syscall"
|
import (
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
func sockaddrToUDP(sa syscall.Sockaddr) Addr {
|
func sockaddrToUDP(sa syscall.Sockaddr) Addr {
|
||||||
switch sa := sa.(type) {
|
switch sa := sa.(type) {
|
||||||
@ -160,6 +163,10 @@ func (c *UDPConn) WriteMsgUDP(b, oob []byte, addr *UDPAddr) (n, oobn int, err er
|
|||||||
// which must be "udp", "udp4", or "udp6". If laddr is not nil, it is used
|
// which must be "udp", "udp4", or "udp6". If laddr is not nil, it is used
|
||||||
// as the local address for the connection.
|
// as the local address for the connection.
|
||||||
func DialUDP(net string, laddr, raddr *UDPAddr) (*UDPConn, error) {
|
func DialUDP(net string, laddr, raddr *UDPAddr) (*UDPConn, error) {
|
||||||
|
return dialUDP(net, laddr, raddr, noDeadline)
|
||||||
|
}
|
||||||
|
|
||||||
|
func dialUDP(net string, laddr, raddr *UDPAddr, deadline time.Time) (*UDPConn, error) {
|
||||||
switch net {
|
switch net {
|
||||||
case "udp", "udp4", "udp6":
|
case "udp", "udp4", "udp6":
|
||||||
default:
|
default:
|
||||||
@ -168,7 +175,7 @@ func DialUDP(net string, laddr, raddr *UDPAddr) (*UDPConn, error) {
|
|||||||
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(), syscall.SOCK_DGRAM, 0, "dial", sockaddrToUDP)
|
fd, err := internetSocket(net, laddr.toAddr(), raddr.toAddr(), deadline, syscall.SOCK_DGRAM, 0, "dial", sockaddrToUDP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -188,7 +195,7 @@ func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error) {
|
|||||||
if laddr == nil {
|
if laddr == nil {
|
||||||
return nil, &OpError{"listen", net, nil, errMissingAddress}
|
return nil, &OpError{"listen", net, nil, errMissingAddress}
|
||||||
}
|
}
|
||||||
fd, err := internetSocket(net, laddr.toAddr(), nil, syscall.SOCK_DGRAM, 0, "listen", sockaddrToUDP)
|
fd, err := internetSocket(net, laddr.toAddr(), nil, noDeadline, syscall.SOCK_DGRAM, 0, "listen", sockaddrToUDP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -208,7 +215,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{"listenmulticast", net, nil, errMissingAddress}
|
return nil, &OpError{"listenmulticast", net, nil, errMissingAddress}
|
||||||
}
|
}
|
||||||
fd, err := internetSocket(net, gaddr.toAddr(), nil, syscall.SOCK_DGRAM, 0, "listen", sockaddrToUDP)
|
fd, err := internetSocket(net, gaddr.toAddr(), nil, noDeadline, syscall.SOCK_DGRAM, 0, "listen", sockaddrToUDP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -139,6 +139,10 @@ func (c *UnixConn) CloseWrite() error {
|
|||||||
// which must be "unix" or "unixgram". If laddr is not nil, it is
|
// which must be "unix" or "unixgram". If laddr is not nil, it is
|
||||||
// used as the local address for the connection.
|
// used as the local address for the connection.
|
||||||
func DialUnix(net string, laddr, raddr *UnixAddr) (*UnixConn, error) {
|
func DialUnix(net string, laddr, raddr *UnixAddr) (*UnixConn, error) {
|
||||||
|
return dialUnix(net, laddr, raddr, noDeadline)
|
||||||
|
}
|
||||||
|
|
||||||
|
func dialUnix(net string, laddr, raddr *UnixAddr, deadline time.Time) (*UnixConn, error) {
|
||||||
return nil, syscall.EPLAN9
|
return nil, syscall.EPLAN9
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func unixSocket(net string, laddr, raddr *UnixAddr, mode string) (fd *netFD, err error) {
|
func unixSocket(net string, laddr, raddr *UnixAddr, mode string, deadline time.Time) (fd *netFD, err error) {
|
||||||
var sotype int
|
var sotype int
|
||||||
switch net {
|
switch net {
|
||||||
default:
|
default:
|
||||||
@ -59,7 +59,7 @@ func unixSocket(net string, laddr, raddr *UnixAddr, mode string) (fd *netFD, err
|
|||||||
f = sockaddrToUnixpacket
|
f = sockaddrToUnixpacket
|
||||||
}
|
}
|
||||||
|
|
||||||
fd, err = socket(net, syscall.AF_UNIX, sotype, 0, false, la, ra, f)
|
fd, err = socket(net, syscall.AF_UNIX, sotype, 0, false, la, ra, deadline, f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
goto Error
|
goto Error
|
||||||
}
|
}
|
||||||
@ -229,7 +229,11 @@ func (c *UnixConn) CloseWrite() error {
|
|||||||
// which must be "unix" or "unixgram". If laddr is not nil, it is used
|
// which must be "unix" or "unixgram". If laddr is not nil, it is used
|
||||||
// as the local address for the connection.
|
// as the local address for the connection.
|
||||||
func DialUnix(net string, laddr, raddr *UnixAddr) (*UnixConn, error) {
|
func DialUnix(net string, laddr, raddr *UnixAddr) (*UnixConn, error) {
|
||||||
fd, err := unixSocket(net, laddr, raddr, "dial")
|
return dialUnix(net, laddr, raddr, noDeadline)
|
||||||
|
}
|
||||||
|
|
||||||
|
func dialUnix(net string, laddr, raddr *UnixAddr, deadline time.Time) (*UnixConn, error) {
|
||||||
|
fd, err := unixSocket(net, laddr, raddr, "dial", deadline)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -253,7 +257,7 @@ func ListenUnix(net string, laddr *UnixAddr) (*UnixListener, error) {
|
|||||||
if laddr != nil {
|
if laddr != nil {
|
||||||
laddr = &UnixAddr{laddr.Name, net} // make our own copy
|
laddr = &UnixAddr{laddr.Name, net} // make our own copy
|
||||||
}
|
}
|
||||||
fd, err := unixSocket(net, laddr, nil, "listen")
|
fd, err := unixSocket(net, laddr, nil, "listen", noDeadline)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -344,7 +348,7 @@ func ListenUnixgram(net string, laddr *UnixAddr) (*UDPConn, error) {
|
|||||||
if laddr == nil {
|
if laddr == nil {
|
||||||
return nil, &OpError{"listen", net, nil, errMissingAddress}
|
return nil, &OpError{"listen", net, nil, errMissingAddress}
|
||||||
}
|
}
|
||||||
fd, err := unixSocket(net, laddr, nil, "listen")
|
fd, err := unixSocket(net, laddr, nil, "listen", noDeadline)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user